mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
Merge remote-tracking branch 'upstream/master' into felica_support_authV1
# Conflicts: # client/cmdhffelica.c
This commit is contained in:
commit
8ce30f54d2
42 changed files with 1711 additions and 547 deletions
|
@ -3,6 +3,12 @@ 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]
|
||||||
|
- Added `hf mf cwipe` magic chinese card (gen1a) wipe to default state (@merlokk)
|
||||||
|
- Added 'pm3_mf7b_wipe.py' python script. Wipes magic S70 7B Gen2 card. (@vulnersCom)
|
||||||
|
- Added `hf mfp chk` Mifare plus command for check keys from public keys list, from dictionary or 1 and 2-byte bruteforce (@merlokk)
|
||||||
|
- Change `hf 15` - some refactoring (@grspy)
|
||||||
|
- Added `hf 15 writeafi` and `hf 15 writedsfid` (@grspy)
|
||||||
|
- Added detailed info for SLIX2 tags in `hf 15 info` (@grspy)
|
||||||
- Fix hf list felica and hf felica sniff (@7homasSutter)
|
- Fix hf list felica and hf felica sniff (@7homasSutter)
|
||||||
- Added hf felica wrunencrypted (@7homasSutter)
|
- Added hf felica wrunencrypted (@7homasSutter)
|
||||||
- Added hf felica rdunencrypted (@7homasSutter)
|
- Added hf felica rdunencrypted (@7homasSutter)
|
||||||
|
|
12
README.md
12
README.md
|
@ -1,14 +1,11 @@
|
||||||
# RRG / Iceman repo - Proxmark3
|
# RRG / Iceman repo - Proxmark3
|
||||||
|
|
||||||
This repo is based on iceman fork for Proxmark3.
|
|
||||||
|
|
||||||
It supports RDV4.0 and other Proxmark3 platforms as well.
|
|
||||||
|
|
||||||
|
|
||||||
| Releases | Linux & OSX CI | Windows CI | Coverity |
|
| Releases | Linux & OSX CI | Windows CI | Coverity |
|
||||||
| ------------------- |:-------------------:| -------------------:| -------------------:|
|
| ------------------- |:-------------------:| -------------------:| -------------------:|
|
||||||
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://travis-ci.org/RfidResearchGroup/proxmark3) | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|
|
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://travis-ci.org/RfidResearchGroup/proxmark3) | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
# PROXMARK INSTALLATION AND OVERVIEW
|
# PROXMARK INSTALLATION AND OVERVIEW
|
||||||
|
|
||||||
|
@ -29,10 +26,12 @@ It supports RDV4.0 and other Proxmark3 platforms as well.
|
||||||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) ||
|
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) ||
|
||||||
|[Donations](#Donations)|||
|
|[Donations](#Donations)|||
|
||||||
|
|
||||||
## Support on other Proxmark3 platforms
|
|
||||||
|
## Build for non-RDV4 Proxmark3 platforms
|
||||||
|
|
||||||
In order to build this repo for other Proxmark3 platforms we urge you to read [Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)
|
In order to build this repo for other Proxmark3 platforms we urge you to read [Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)
|
||||||
|
|
||||||
|
|
||||||
## What has changed?
|
## What has changed?
|
||||||
|
|
||||||
On the hardware side:
|
On the hardware side:
|
||||||
|
@ -110,4 +109,3 @@ Nothing says thank you as much as a donation. So if you feel the love, do feel f
|
||||||
|
|
||||||
https://www.patreon.com/iceman1001
|
https://www.patreon.com/iceman1001
|
||||||
|
|
||||||
All support is welcome!
|
|
||||||
|
|
|
@ -929,6 +929,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
||||||
uint8_t buf[ISO15_MAX_FRAME];
|
uint8_t buf[ISO15_MAX_FRAME];
|
||||||
memset(buf, 0x00, sizeof(buf));
|
memset(buf, 0x00, sizeof(buf));
|
||||||
int datalen = 0, recvlen = 0;
|
int datalen = 0, recvlen = 0;
|
||||||
|
bool aborted = false;
|
||||||
|
|
||||||
Iso15693InitReader();
|
Iso15693InitReader();
|
||||||
|
|
||||||
|
@ -966,7 +967,9 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
||||||
Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2));
|
Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BUTTON_PRESS()) {
|
aborted = BUTTON_PRESS();
|
||||||
|
|
||||||
|
if (aborted) {
|
||||||
DbpString("button pressed, aborting..");
|
DbpString("button pressed, aborting..");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -974,6 +977,12 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
||||||
|
|
||||||
DbpString("AFI Bruteforcing done.");
|
DbpString("AFI Bruteforcing done.");
|
||||||
switch_off();
|
switch_off();
|
||||||
|
|
||||||
|
if (aborted) {
|
||||||
|
reply_ng(CMD_ACK, PM3_EOPABORTED, NULL, 0);
|
||||||
|
} else {
|
||||||
|
reply_ng(CMD_ACK, PM3_SUCCESS, NULL, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allows to directly send commands to the tag via the client
|
// Allows to directly send commands to the tag via the client
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "crc16.h"
|
#include "crc16.h"
|
||||||
#include "dbprint.h"
|
#include "dbprint.h"
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
|
#include "usb_cdc.h" // usb_poll_validate_length
|
||||||
|
|
||||||
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
|
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
|
||||||
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
||||||
|
@ -918,7 +919,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
||||||
for (rtr = 0; rtr < 17; rtr++) {
|
for (rtr = 0; rtr < 17; rtr++) {
|
||||||
|
|
||||||
// Test if the action was cancelled
|
// Test if the action was cancelled
|
||||||
if (BUTTON_PRESS()) {
|
if (BUTTON_PRESS() || usb_poll_validate_length()) {
|
||||||
isOK = -2;
|
isOK = -2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -998,6 +999,12 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
||||||
target_nt[i] = 0;
|
target_nt[i] = 0;
|
||||||
while (target_nt[i] == 0) { // continue until we have an unambiguous nonce
|
while (target_nt[i] == 0) { // continue until we have an unambiguous nonce
|
||||||
|
|
||||||
|
// Test if the action was cancelled
|
||||||
|
if (BUTTON_PRESS() || usb_poll_validate_length()) {
|
||||||
|
isOK = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// prepare next select. No need to power down the card.
|
// prepare next select. No need to power down the card.
|
||||||
if (mifare_classic_halt(pcs, cuid)) {
|
if (mifare_classic_halt(pcs, cuid)) {
|
||||||
if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Halt error");
|
if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Halt error");
|
||||||
|
|
|
@ -134,6 +134,7 @@ CORESRCS = uart_posix.c \
|
||||||
|
|
||||||
CMDSRCS = crapto1/crapto1.c \
|
CMDSRCS = crapto1/crapto1.c \
|
||||||
crapto1/crypto1.c \
|
crapto1/crypto1.c \
|
||||||
|
mifare/mifaredefault.c \
|
||||||
mifare/mfkey.c \
|
mifare/mfkey.c \
|
||||||
tea.c \
|
tea.c \
|
||||||
fido/additional_ca.c \
|
fido/additional_ca.c \
|
||||||
|
|
|
@ -406,7 +406,7 @@ static int CmdSetDebugMode(const char *Cmd) {
|
||||||
void printDemodBuff(void) {
|
void printDemodBuff(void) {
|
||||||
int len = DemodBufferLen;
|
int len = DemodBufferLen;
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
PrintAndLogEx(NORMAL, "(printDemodBuff) no bits found in demod buffer");
|
PrintAndLogEx(INFO, "(printDemodBuff) no bits found in demod buffer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (len > 512) len = 512;
|
if (len > 512) len = 512;
|
||||||
|
@ -458,7 +458,7 @@ int CmdPrintDemodBuff(const char *Cmd) {
|
||||||
if (errors) return usage_data_printdemodbuf();
|
if (errors) return usage_data_printdemodbuf();
|
||||||
|
|
||||||
if (DemodBufferLen == 0) {
|
if (DemodBufferLen == 0) {
|
||||||
PrintAndLogEx(NORMAL, "Demodbuffer is empty");
|
PrintAndLogEx(WARNING, "Demodbuffer is empty");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
if (lstrip) {
|
if (lstrip) {
|
||||||
|
@ -491,9 +491,9 @@ int CmdPrintDemodBuff(const char *Cmd) {
|
||||||
if (numBits == 0) {
|
if (numBits == 0) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "DemodBuffer: %s", hex);
|
PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32));
|
PrintAndLogEx(SUCCESS, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32));
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||||
if (cmdp == 'h') return usage_hf_search();
|
if (cmdp == 'h') return usage_hf_search();
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Checking for known tags...\n");
|
PrintAndLogEx(INFO, "Checking for known tags...");
|
||||||
|
|
||||||
PROMPT_CLEARLINE;
|
PROMPT_CLEARLINE;
|
||||||
PrintAndLogEx(INPLACE, "Searching for ThinFilm tag...");
|
PrintAndLogEx(INPLACE, "Searching for ThinFilm tag...");
|
||||||
|
@ -100,13 +100,10 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
PROMPT_CLEARLINE;
|
PROMPT_CLEARLINE;
|
||||||
PrintAndLogEx(INPLACE, "Searching for ISO15693 tag...");
|
PrintAndLogEx(INPLACE, "Searching for ISO15693 tag...");
|
||||||
if (IfPm3Iso15693()) {
|
if (IfPm3Iso15693()) {
|
||||||
if (readHF15Uid(false) == 1) {
|
if (readHF15Uid(false)) {
|
||||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") " found\n");
|
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") " found\n");
|
||||||
DropField();
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
// until refactoring of ISO15693 cmds, this is needed.
|
|
||||||
DropField();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PROMPT_CLEARLINE;
|
PROMPT_CLEARLINE;
|
||||||
|
@ -155,8 +152,10 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INPLACE, "No known/supported 13.56 MHz tags found");
|
PROMPT_CLEARLINE;
|
||||||
|
PrintAndLogEx(INPLACE, "done");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(FAILED, _RED_("No known/supported 13.56 MHz tags found"));
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +165,7 @@ int CmdHFTune(const char *Cmd) {
|
||||||
int iter = param_get32ex(Cmd, 0, 0, 10);
|
int iter = param_get32ex(Cmd, 0, 0, 10);
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
PrintAndLogEx(SUCCESS, "Measuring HF antenna, click button or press Enter to exit");
|
PrintAndLogEx(SUCCESS, "Measuring HF antenna," _YELLOW_("click button") " or press" _YELLOW_("Enter") "to exit");
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
uint8_t mode[] = {1};
|
uint8_t mode[] = {1};
|
||||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
|
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
|
||||||
|
|
|
@ -256,20 +256,20 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select_status == 3) {
|
if (select_status == 3) {
|
||||||
PrintAndLogEx(NORMAL, "E->Card doesn't support standard iso14443-3 anticollision");
|
PrintAndLogEx(INFO, "E->Card doesn't support standard iso14443-3 anticollision");
|
||||||
PrintAndLogEx(NORMAL, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]);
|
PrintAndLogEx(SUCCESS, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(card->uid, card->uidlen));
|
PrintAndLogEx(SUCCESS, " UID: %s", sprint_hex(card->uid, card->uidlen));
|
||||||
PrintAndLogEx(NORMAL, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]);
|
PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]);
|
||||||
PrintAndLogEx(NORMAL, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]);
|
PrintAndLogEx(SUCCESS, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]);
|
||||||
if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||||
PrintAndLogEx(NORMAL, "E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len));
|
PrintAndLogEx(INFO, "E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " ATS: %s", sprint_hex(card->ats, card->ats_len));
|
PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card->ats, card->ats_len));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,18 +334,18 @@ static int CmdHF14AReader(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select_status == 3) {
|
if (select_status == 3) {
|
||||||
PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision");
|
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
|
||||||
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||||
DropField();
|
DropField();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||||
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||||
PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
|
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
|
||||||
|
|
||||||
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||||
PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len));
|
PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!disconnectAfter) {
|
if (!disconnectAfter) {
|
||||||
|
@ -422,7 +422,7 @@ static int CmdHF14ACUIDs(const char *Cmd) {
|
||||||
for (uint16_t m = 0; m < card->uidlen; m++) {
|
for (uint16_t m = 0; m < card->uidlen; m++) {
|
||||||
sprintf(&uid_string[2 * m], "%02X", card->uid[m]);
|
sprintf(&uid_string[2 * m], "%02X", card->uid[m]);
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "%s", uid_string);
|
PrintAndLogEx(SUCCESS, "%s", uid_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock() - t1) / 1000);
|
PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock() - t1) / 1000);
|
||||||
|
@ -528,9 +528,9 @@ int CmdHF14ASim(const char *Cmd) {
|
||||||
|
|
||||||
if (keypress && (flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
|
if (keypress && (flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) {
|
||||||
// inform device to break the sim loop since client has exited
|
// inform device to break the sim loop since client has exited
|
||||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK))
|
if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK))
|
||||||
showSectorTable();
|
showSectorTable();
|
||||||
|
|
||||||
|
@ -551,30 +551,29 @@ int CmdHF14ASniff(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode) {
|
||||||
static uint8_t responseNum = 0;
|
static uint8_t responseNum = 0;
|
||||||
uint16_t cmdc = 0;
|
uint16_t cmdc = 0;
|
||||||
*dataoutlen = 0;
|
*dataoutlen = 0;
|
||||||
|
|
||||||
if (activateField) {
|
if (activateField) {
|
||||||
responseNum = 1;
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
||||||
// Anticollision + SELECT card
|
// Anticollision + SELECT card
|
||||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
|
if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check result
|
// check result
|
||||||
if (resp.oldarg[0] == 0) {
|
if (resp.oldarg[0] == 0) {
|
||||||
PrintAndLogEx(ERR, "No card in field.");
|
if (!silentMode) PrintAndLogEx(ERR, "No card in field.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) {
|
if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) {
|
||||||
PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]);
|
if (!silentMode) PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,12 +582,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
|
||||||
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
||||||
SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2);
|
SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2);
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
|
if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.oldarg[0] == 0) { // ats_len
|
if (resp.oldarg[0] == 0) { // ats_len
|
||||||
PrintAndLogEx(ERR, "Can't get ATS.");
|
if (!silentMode) PrintAndLogEx(ERR, "Can't get ATS.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,7 +609,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
|
||||||
int iLen = resp.oldarg[0];
|
int iLen = resp.oldarg[0];
|
||||||
|
|
||||||
if (!iLen) {
|
if (!iLen) {
|
||||||
PrintAndLogEx(ERR, "No card response.");
|
if (!silentMode) PrintAndLogEx(ERR, "No card response.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,12 +618,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
|
||||||
*dataoutlen = 0;
|
*dataoutlen = 0;
|
||||||
|
|
||||||
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
|
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
|
||||||
PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
|
if (!silentMode) PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv[0] != data[0]) {
|
if (recv[0] != data[0]) {
|
||||||
PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]);
|
if (!silentMode) PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,12 +631,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
|
||||||
|
|
||||||
// CRC Check
|
// CRC Check
|
||||||
if (iLen == -1) {
|
if (iLen == -1) {
|
||||||
PrintAndLogEx(ERR, "ISO 14443A CRC error.");
|
if (!silentMode) PrintAndLogEx(ERR, "ISO 14443A CRC error.");
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "Reply timeout.");
|
if (!silentMode) PrintAndLogEx(ERR, "Reply timeout.");
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1273,16 +1272,18 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
return select_status;
|
return select_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
if (select_status == 3) {
|
if (select_status == 3) {
|
||||||
PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision");
|
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
|
||||||
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||||
DropField();
|
DropField();
|
||||||
return select_status;
|
return select_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||||
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||||
PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
|
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
|
||||||
|
|
||||||
bool isMifareClassic = true;
|
bool isMifareClassic = true;
|
||||||
switch (card.sak) {
|
switch (card.sak) {
|
||||||
|
@ -1296,7 +1297,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
if (tagT != UL_ERROR)
|
if (tagT != UL_ERROR)
|
||||||
ul_print_type(tagT, 0);
|
ul_print_type(tagT, 0);
|
||||||
else
|
else
|
||||||
PrintAndLogEx(NORMAL, "TYPE: Possible AZTEK (iso14443a compliant)");
|
PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)");
|
||||||
|
|
||||||
// reconnect for further tests
|
// reconnect for further tests
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
|
@ -1313,49 +1314,49 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP TNP3xxx Activision Game Appliance");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance");
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)");
|
||||||
isMifareClassic = false;
|
isMifareClassic = false;
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1");
|
||||||
break;
|
break;
|
||||||
case 0x09:
|
case 0x09:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Mini 0.3k");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k");
|
||||||
break;
|
break;
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : FM11RF005SH (Shanghai Metro)");
|
PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)");
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 2k SL2");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2");
|
||||||
break;
|
break;
|
||||||
case 0x11:
|
case 0x11:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 4k SL2");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2");
|
||||||
break;
|
break;
|
||||||
case 0x18:
|
case 0x18:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1");
|
||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41");
|
||||||
isMifareClassic = false;
|
isMifareClassic = false;
|
||||||
break;
|
break;
|
||||||
case 0x24:
|
case 0x24:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire | DESFire EV1");
|
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1");
|
||||||
isMifareClassic = false;
|
isMifareClassic = false;
|
||||||
break;
|
break;
|
||||||
case 0x28:
|
case 0x28:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : JCOP31 or JCOP41 v2.3.1");
|
PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1");
|
||||||
break;
|
break;
|
||||||
case 0x38:
|
case 0x38:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K");
|
PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K");
|
||||||
break;
|
break;
|
||||||
case 0x88:
|
case 0x88:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : Infineon MIFARE CLASSIC 1K");
|
PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K");
|
||||||
break;
|
break;
|
||||||
case 0x98:
|
case 0x98:
|
||||||
PrintAndLogEx(NORMAL, "TYPE : Gemplus MPCOS");
|
PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
|
@ -1363,7 +1364,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
|
|
||||||
// Double & triple sized UID, can be mapped to a manufacturer.
|
// Double & triple sized UID, can be mapped to a manufacturer.
|
||||||
if (card.uidlen > 4) {
|
if (card.uidlen > 4) {
|
||||||
PrintAndLogEx(NORMAL, "MANUFACTURER : %s", getTagInfo(card.uid[0]));
|
PrintAndLogEx(SUCCESS, "MANUFACTURER : %s", getTagInfo(card.uid[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to request ATS even if tag claims not to support it
|
// try to request ATS even if tag claims not to support it
|
||||||
|
@ -1382,12 +1383,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
if (select_status == 2) {
|
if (select_status == 2) {
|
||||||
PrintAndLogEx(NORMAL, "SAK incorrectly claims that card doesn't support RATS");
|
PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS");
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len));
|
PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len));
|
||||||
PrintAndLogEx(NORMAL, " - TL : length is %d bytes", card.ats[0]);
|
PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]);
|
||||||
if (card.ats[0] != card.ats_len - 2) {
|
if (card.ats[0] != card.ats_len - 2) {
|
||||||
PrintAndLogEx(NORMAL, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
|
PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card.ats[0] > 1) { // there is a format byte (T0)
|
if (card.ats[0] > 1) { // there is a format byte (T0)
|
||||||
|
@ -1396,7 +1397,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
tc1 = (card.ats[1] & 0x40) == 0x40;
|
tc1 = (card.ats[1] & 0x40) == 0x40;
|
||||||
int16_t fsci = card.ats[1] & 0x0f;
|
int16_t fsci = card.ats[1] & 0x0f;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " - T0 : TA1 is%s present, TB1 is%s present, "
|
PrintAndLogEx(SUCCESS, " - T0 : TA1 is%s present, TB1 is%s present, "
|
||||||
"TC1 is%s present, FSCI is %d (FSC = %d)",
|
"TC1 is%s present, FSCI is %d (FSC = %d)",
|
||||||
(ta1 ? "" : " NOT"),
|
(ta1 ? "" : " NOT"),
|
||||||
(tb1 ? "" : " NOT"),
|
(tb1 ? "" : " NOT"),
|
||||||
|
@ -1417,7 +1418,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
if (card.ats[pos] & 0x04) strcat(dr, "8, ");
|
if (card.ats[pos] & 0x04) strcat(dr, "8, ");
|
||||||
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
|
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
|
||||||
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
|
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
|
||||||
PrintAndLogEx(NORMAL, " - TA1 : different divisors are%s supported, "
|
PrintAndLogEx(SUCCESS, " - TA1 : different divisors are%s supported, "
|
||||||
"DR: [%s], DS: [%s]",
|
"DR: [%s], DS: [%s]",
|
||||||
((card.ats[pos] & 0x80) ? " NOT" : ""),
|
((card.ats[pos] & 0x80) ? " NOT" : ""),
|
||||||
dr,
|
dr,
|
||||||
|
@ -1429,7 +1430,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
if (tb1) {
|
if (tb1) {
|
||||||
uint32_t sfgi = card.ats[pos] & 0x0F;
|
uint32_t sfgi = card.ats[pos] & 0x0F;
|
||||||
uint32_t fwi = card.ats[pos] >> 4;
|
uint32_t fwi = card.ats[pos] >> 4;
|
||||||
PrintAndLogEx(NORMAL, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)",
|
PrintAndLogEx(SUCCESS, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)",
|
||||||
(sfgi),
|
(sfgi),
|
||||||
sfgi ? "" : "(not needed) ",
|
sfgi ? "" : "(not needed) ",
|
||||||
sfgi ? (1 << 12) << sfgi : 0,
|
sfgi ? (1 << 12) << sfgi : 0,
|
||||||
|
@ -1439,7 +1440,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
if (tc1) {
|
if (tc1) {
|
||||||
PrintAndLogEx(NORMAL, " - TC1 : NAD is%s supported, CID is%s supported",
|
PrintAndLogEx(SUCCESS, " - TC1 : NAD is%s supported, CID is%s supported",
|
||||||
(card.ats[pos] & 0x01) ? "" : " NOT",
|
(card.ats[pos] & 0x01) ? "" : " NOT",
|
||||||
(card.ats[pos] & 0x02) ? "" : " NOT");
|
(card.ats[pos] & 0x02) ? "" : " NOT");
|
||||||
pos++;
|
pos++;
|
||||||
|
@ -1453,63 +1454,63 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
tip = "-> MIFARE Plus S 2K or 4K";
|
tip = "-> MIFARE Plus S 2K or 4K";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip);
|
PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip);
|
||||||
if (card.ats[pos] == 0xC1) {
|
if (card.ats[pos] == 0xC1) {
|
||||||
PrintAndLogEx(NORMAL, " c1 -> Mifare or (multiple) virtual cards of various type");
|
PrintAndLogEx(SUCCESS, " c1 -> Mifare or (multiple) virtual cards of various type");
|
||||||
PrintAndLogEx(NORMAL, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]);
|
PrintAndLogEx(SUCCESS, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]);
|
||||||
switch (card.ats[pos + 2] & 0xf0) {
|
switch (card.ats[pos + 2] & 0xf0) {
|
||||||
case 0x10:
|
case 0x10:
|
||||||
PrintAndLogEx(NORMAL, " 1x -> MIFARE DESFire");
|
PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire");
|
||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
PrintAndLogEx(NORMAL, " 2x -> MIFARE Plus");
|
PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (card.ats[pos + 2] & 0x0f) {
|
switch (card.ats[pos + 2] & 0x0f) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " x0 -> <1 kByte");
|
PrintAndLogEx(SUCCESS, " x0 -> <1 kByte");
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " x1 -> 1 kByte");
|
PrintAndLogEx(SUCCESS, " x1 -> 1 kByte");
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
PrintAndLogEx(NORMAL, " x2 -> 2 kByte");
|
PrintAndLogEx(SUCCESS, " x2 -> 2 kByte");
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
PrintAndLogEx(NORMAL, " x3 -> 4 kByte");
|
PrintAndLogEx(SUCCESS, " x3 -> 4 kByte");
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
PrintAndLogEx(NORMAL, " x4 -> 8 kByte");
|
PrintAndLogEx(SUCCESS, " x4 -> 8 kByte");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (card.ats[pos + 3] & 0xf0) {
|
switch (card.ats[pos + 3] & 0xf0) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " 0x -> Engineering sample");
|
PrintAndLogEx(SUCCESS, " 0x -> Engineering sample");
|
||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
PrintAndLogEx(NORMAL, " 2x -> Released");
|
PrintAndLogEx(SUCCESS, " 2x -> Released");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (card.ats[pos + 3] & 0x0f) {
|
switch (card.ats[pos + 3] & 0x0f) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " x0 -> Generation 1");
|
PrintAndLogEx(SUCCESS, " x0 -> Generation 1");
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " x1 -> Generation 2");
|
PrintAndLogEx(SUCCESS, " x1 -> Generation 2");
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
PrintAndLogEx(NORMAL, " x2 -> Generation 3");
|
PrintAndLogEx(SUCCESS, " x2 -> Generation 3");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (card.ats[pos + 4] & 0x0f) {
|
switch (card.ats[pos + 4] & 0x0f) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " x0 -> Only VCSL supported");
|
PrintAndLogEx(SUCCESS, " x0 -> Only VCSL supported");
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " x1 -> VCS, VCSL, and SVC supported");
|
PrintAndLogEx(SUCCESS, " x1 -> VCS, VCSL, and SVC supported");
|
||||||
break;
|
break;
|
||||||
case 0x0E:
|
case 0x0E:
|
||||||
PrintAndLogEx(NORMAL, " xE -> no VCS command supported");
|
PrintAndLogEx(SUCCESS, " xE -> no VCS command supported");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1552,9 +1553,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
|
|
||||||
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
|
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
|
||||||
if (sw == 0x9000) {
|
if (sw == 0x9000) {
|
||||||
if (verbose) PrintAndLogEx(NORMAL, "------------- Application OK -----------");
|
if (verbose) PrintAndLogEx(SUCCESS, "------------- Application OK -----------");
|
||||||
} else {
|
} else {
|
||||||
if (verbose) PrintAndLogEx(NORMAL, "----------- Application blocked --------");
|
if (verbose) PrintAndLogEx(WARNING, "----------- Application blocked --------");
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose);
|
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
// 2011, Merlok
|
// 2011,2019 Merlok
|
||||||
// 2015,216,2017 iceman, marshmellow, piwi
|
// 2015,2016,2017 iceman, marshmellow, piwi
|
||||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
// the license.
|
// the license.
|
||||||
|
@ -30,6 +30,6 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);
|
||||||
const char *getTagInfo(uint8_t uid);
|
const char *getTagInfo(uint8_t uid);
|
||||||
int Hf14443_4aGetCardData(iso14a_card_select_t *card);
|
int Hf14443_4aGetCardData(iso14a_card_select_t *card);
|
||||||
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||||
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -528,9 +528,10 @@ static bool HF14B_Std_Info(bool verbose) {
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||||
PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid);
|
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||||
|
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
|
||||||
print_atqb_resp(card.atqb, card.cid);
|
print_atqb_resp(card.atqb, card.cid);
|
||||||
isSuccess = true;
|
isSuccess = true;
|
||||||
break;
|
break;
|
||||||
|
@ -662,9 +663,10 @@ static bool HF14B_Std_Reader(bool verbose) {
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||||
PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid);
|
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||||
|
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
|
||||||
print_atqb_resp(card.atqb, card.cid);
|
print_atqb_resp(card.atqb, card.cid);
|
||||||
isSuccess = true;
|
isSuccess = true;
|
||||||
break;
|
break;
|
||||||
|
@ -808,13 +810,13 @@ static int CmdHF14BWriteSri(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockno == 0xff) {
|
if (blockno == 0xff) {
|
||||||
PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ %s ]",
|
PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ " _YELLOW_("%s")" ]",
|
||||||
(isSrix4k) ? "SRIX4K" : "SRI512",
|
(isSrix4k) ? "SRIX4K" : "SRI512",
|
||||||
blockno,
|
blockno,
|
||||||
sprint_hex(data, 4)
|
sprint_hex(data, 4)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ %s ]",
|
PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ " _YELLOW_("%s")" ]",
|
||||||
(isSrix4k) ? "SRIX4K" : "SRI512",
|
(isSrix4k) ? "SRIX4K" : "SRI512",
|
||||||
blockno,
|
blockno,
|
||||||
sprint_hex(data, 4)
|
sprint_hex(data, 4)
|
||||||
|
|
574
client/cmdhf15.c
574
client/cmdhf15.c
|
@ -31,6 +31,7 @@
|
||||||
#include "comms.h" // clearCommandBuffer
|
#include "comms.h" // clearCommandBuffer
|
||||||
#include "cmdtrace.h"
|
#include "cmdtrace.h"
|
||||||
#include "iso15693tools.h"
|
#include "iso15693tools.h"
|
||||||
|
#include "crypto/libpcrypto.h"
|
||||||
|
|
||||||
#include "graph.h"
|
#include "graph.h"
|
||||||
#include "crc16.h" // iso15 crc
|
#include "crc16.h" // iso15 crc
|
||||||
|
@ -207,10 +208,20 @@ const productName uidmapping[] = {
|
||||||
{ 0, 0, "no tag-info available" } // must be the last entry
|
{ 0, 0, "no tag-info available" } // must be the last entry
|
||||||
};
|
};
|
||||||
|
|
||||||
// fast method to just read the UID of a tag (collission detection not supported)
|
uint8_t nxp_public_keys[][33] = {
|
||||||
|
// ICODE SLIX2 / DNA
|
||||||
|
{
|
||||||
|
0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
|
||||||
|
0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71,
|
||||||
|
0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
|
||||||
|
0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// fast method to just read the UID of a tag (collision detection not supported)
|
||||||
// *buf should be large enough to fit the 64bit uid
|
// *buf should be large enough to fit the 64bit uid
|
||||||
// returns 1 if suceeded
|
// returns 1 if succeeded
|
||||||
static int getUID(uint8_t *buf) {
|
static bool getUID(uint8_t *buf) {
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
uint8_t data[5];
|
uint8_t data[5];
|
||||||
|
@ -233,12 +244,14 @@ static int getUID(uint8_t *buf) {
|
||||||
uint8_t resplen = resp.oldarg[0];
|
uint8_t resplen = resp.oldarg[0];
|
||||||
if (resplen >= 12 && CheckCrc15(resp.data.asBytes, 12)) {
|
if (resplen >= 12 && CheckCrc15(resp.data.asBytes, 12)) {
|
||||||
memcpy(buf, resp.data.asBytes + 2, 8);
|
memcpy(buf, resp.data.asBytes + 2, 8);
|
||||||
return 1;
|
DropField();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // retry
|
} // retry
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
DropField();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a product description based on the UID
|
// get a product description based on the UID
|
||||||
|
@ -273,7 +286,7 @@ static const char *TagErrorStr(uint8_t error) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
return "The command is not supported";
|
return "The command is not supported";
|
||||||
case 0x02:
|
case 0x02:
|
||||||
return "The command is not recognised";
|
return "The command is not recognized";
|
||||||
case 0x03:
|
case 0x03:
|
||||||
return "The option is not supported.";
|
return "The option is not supported.";
|
||||||
case 0x0f:
|
case 0x0f:
|
||||||
|
@ -349,6 +362,24 @@ static int usage_15_findafi(void) {
|
||||||
"Usage: hf 15 findafi");
|
"Usage: hf 15 findafi");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
static int usage_15_writeafi(void) {
|
||||||
|
PrintAndLogEx(NORMAL, "Usage: hf 15 writeafi <uid|u|*> <afi#>\n"
|
||||||
|
"\tuid (either): \n"
|
||||||
|
"\t <8B hex> full UID eg E011223344556677\n"
|
||||||
|
"\t u unaddressed mode\n"
|
||||||
|
"\t * scan for tag\n"
|
||||||
|
"\tafi#: AFI number 0-255");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
static int usage_15_writedsfid(void) {
|
||||||
|
PrintAndLogEx(NORMAL, "Usage: hf 15 writedsfid <uid|u|*> <dsfid#>\n"
|
||||||
|
"\tuid (either): \n"
|
||||||
|
"\t <8B hex> full UID eg E011223344556677\n"
|
||||||
|
"\t u unaddressed mode\n"
|
||||||
|
"\t * scan for tag\n"
|
||||||
|
"\tdsfid#: DSFID number 0-255");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
static int usage_15_dump(void) {
|
static int usage_15_dump(void) {
|
||||||
PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-15693 tag and save it to file\n"
|
PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-15693 tag and save it to file\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -381,6 +412,7 @@ static int usage_15_raw(void) {
|
||||||
{"-r", "do not read response" },
|
{"-r", "do not read response" },
|
||||||
{"-2", "use slower '1 out of 256' mode" },
|
{"-2", "use slower '1 out of 256' mode" },
|
||||||
{"-c", "calculate and append CRC" },
|
{"-c", "calculate and append CRC" },
|
||||||
|
{"-p", "leave the signal field ON" },
|
||||||
{"", "Tip: turn on debugging for verbose output"},
|
{"", "Tip: turn on debugging for verbose output"},
|
||||||
};
|
};
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf 15 raw [-r] [-2] [-c] <0A 0B 0C ... hex>\n");
|
PrintAndLogEx(NORMAL, "Usage: hf 15 raw [-r] [-2] [-c] <0A 0B 0C ... hex>\n");
|
||||||
|
@ -440,7 +472,7 @@ static int usage_15_csetuid(void) {
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* **cmd command line
|
* **cmd command line
|
||||||
*/
|
*/
|
||||||
static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0
|
static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0
|
||||||
int temp;
|
int temp;
|
||||||
uint8_t uid[8] = {0x00};
|
uint8_t uid[8] = {0x00};
|
||||||
uint32_t tmpreqlen = 0;
|
uint32_t tmpreqlen = 0;
|
||||||
|
@ -467,7 +499,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *
|
||||||
switch (**cmd) {
|
switch (**cmd) {
|
||||||
case 0:
|
case 0:
|
||||||
PrintAndLogEx(WARNING, "missing addr");
|
PrintAndLogEx(WARNING, "missing addr");
|
||||||
return 0;
|
return false;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'U':
|
case 'U':
|
||||||
|
@ -482,10 +514,10 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *
|
||||||
|
|
||||||
if (!getUID(uid)) {
|
if (!getUID(uid)) {
|
||||||
PrintAndLogEx(WARNING, "No tag found");
|
PrintAndLogEx(WARNING, "No tag found");
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy(&req[tmpreqlen], uid, sizeof(uid));
|
memcpy(&req[tmpreqlen], uid, sizeof(uid));
|
||||||
PrintAndLogEx(NORMAL, "Detected UID %s", sprintUID(NULL, uid));
|
PrintAndLogEx(SUCCESS, "Detected UID %s", sprintUID(NULL, uid));
|
||||||
tmpreqlen += sizeof(uid);
|
tmpreqlen += sizeof(uid);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -498,7 +530,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *
|
||||||
uid[7 - i] = temp & 0xff;
|
uid[7 - i] = temp & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Using UID %s", sprintUID(NULL, uid));
|
PrintAndLogEx(SUCCESS, "Using UID %s", sprintUID(NULL, uid));
|
||||||
memcpy(&req[tmpreqlen], uid, sizeof(uid));
|
memcpy(&req[tmpreqlen], uid, sizeof(uid));
|
||||||
tmpreqlen += sizeof(uid);
|
tmpreqlen += sizeof(uid);
|
||||||
break;
|
break;
|
||||||
|
@ -509,7 +541,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *
|
||||||
while (**cmd == ' ' || **cmd == '\t')(*cmd)++;
|
while (**cmd == ' ' || **cmd == '\t')(*cmd)++;
|
||||||
|
|
||||||
*reqlen = tmpreqlen;
|
*reqlen = tmpreqlen;
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode 3
|
// Mode 3
|
||||||
|
@ -523,7 +555,7 @@ static int CmdHF15Demod(const char *Cmd) {
|
||||||
int max = 0, maxPos = 0;
|
int max = 0, maxPos = 0;
|
||||||
int skip = 4;
|
int skip = 4;
|
||||||
|
|
||||||
if (GraphTraceLen < 1000) return 0;
|
if (GraphTraceLen < 1000) return PM3_ESOFT;
|
||||||
|
|
||||||
// First, correlate for SOF
|
// First, correlate for SOF
|
||||||
for (i = 0; i < 1000; i++) {
|
for (i = 0; i < 1000; i++) {
|
||||||
|
@ -537,7 +569,7 @@ static int CmdHF15Demod(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "SOF at %d, correlation %zu", maxPos, max / (ARRAYLEN(FrameSOF) / skip));
|
PrintAndLogEx(INFO, "SOF at %d, correlation %zu", maxPos, max / (ARRAYLEN(FrameSOF) / skip));
|
||||||
|
|
||||||
i = maxPos + ARRAYLEN(FrameSOF) / skip;
|
i = maxPos + ARRAYLEN(FrameSOF) / skip;
|
||||||
int k = 0;
|
int k = 0;
|
||||||
|
@ -560,7 +592,7 @@ static int CmdHF15Demod(const char *Cmd) {
|
||||||
corr1 *= 4;
|
corr1 *= 4;
|
||||||
|
|
||||||
if (corrEOF > corr1 && corrEOF > corr0) {
|
if (corrEOF > corr1 && corrEOF > corr0) {
|
||||||
PrintAndLogEx(NORMAL, "EOF at %d", i);
|
PrintAndLogEx(INFO, "EOF at %d", i);
|
||||||
break;
|
break;
|
||||||
} else if (corr1 > corr0) {
|
} else if (corr1 > corr0) {
|
||||||
i += ARRAYLEN(Logic1) / skip;
|
i += ARRAYLEN(Logic1) / skip;
|
||||||
|
@ -574,22 +606,22 @@ static int CmdHF15Demod(const char *Cmd) {
|
||||||
mask = 0x01;
|
mask = 0x01;
|
||||||
}
|
}
|
||||||
if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) {
|
if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) {
|
||||||
PrintAndLogEx(NORMAL, "ran off end!");
|
PrintAndLogEx(INFO, "ran off end!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask != 0x01) {
|
if (mask != 0x01) {
|
||||||
PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)");
|
PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)");
|
||||||
PrintAndLogEx(NORMAL, " mask = %02x", mask);
|
PrintAndLogEx(INFO, " mask = %02x", mask);
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "%d octets", k);
|
PrintAndLogEx(INFO, "%d octets", k);
|
||||||
|
|
||||||
for (i = 0; i < k; i++)
|
for (i = 0; i < k; i++)
|
||||||
PrintAndLogEx(NORMAL, "# %2d: %02x ", i, outBuf[i]);
|
PrintAndLogEx(SUCCESS, "# %2d: %02x ", i, outBuf[i]);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "CRC %04x", Crc15(outBuf, k - 2));
|
PrintAndLogEx(SUCCESS, "CRC %04x", Crc15(outBuf, k - 2));
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// * Acquire Samples as Reader (enables carrier, sends inquiry)
|
// * Acquire Samples as Reader (enables carrier, sends inquiry)
|
||||||
|
@ -602,7 +634,181 @@ static int CmdHF15Samples(const char *Cmd) {
|
||||||
SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0);
|
SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0);
|
||||||
|
|
||||||
getSamples(0, false);
|
getSamples(0, false);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get NXP system information from SLIX2 tag/VICC
|
||||||
|
static int NxpSysInfo(uint8_t *uid) {
|
||||||
|
PacketResponseNG resp;
|
||||||
|
uint8_t *recv;
|
||||||
|
uint8_t req[PM3_CMD_DATA_SIZE] = {0};
|
||||||
|
uint16_t reqlen;
|
||||||
|
uint8_t arg1 = 1;
|
||||||
|
|
||||||
|
if (uid != NULL) {
|
||||||
|
reqlen = 0;
|
||||||
|
req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
|
||||||
|
req[reqlen++] = ISO15_CMD_GETNXPSYSTEMINFO;
|
||||||
|
req[reqlen++] = 0x04; // IC manufacturer code
|
||||||
|
memcpy(req + 3, uid, 8); // add UID
|
||||||
|
reqlen += 8;
|
||||||
|
|
||||||
|
AddCrc15(req, reqlen);
|
||||||
|
reqlen += 2;
|
||||||
|
|
||||||
|
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||||
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
PrintAndLogEx(WARNING, "iso15693 card select failed");
|
||||||
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
uint32_t status = resp.oldarg[0];
|
||||||
|
|
||||||
|
if (status < 2) {
|
||||||
|
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command");
|
||||||
|
return PM3_EWRONGANSVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
|
return PM3_EWRONGANSVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool signature = false;
|
||||||
|
bool easmode = false;
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(NORMAL, " NXP SYSINFO : %s", sprint_hex(recv, 8));
|
||||||
|
PrintAndLogEx(NORMAL, " Password protection configuration:");
|
||||||
|
PrintAndLogEx(NORMAL, " * Page L read%s password protected", (recv[2] & 0x01 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * Page L write%s password protected", (recv[2] & 0x02 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * Page H read%s password protected", (recv[2] & 0x08 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * Page H write%s password protected", (recv[2] & 0x20 ? "" : " not"));
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, " Lock bits:");
|
||||||
|
PrintAndLogEx(NORMAL, " * AFI%s locked", (recv[3] & 0x01 ? "" : " not")); // AFI lock bit
|
||||||
|
PrintAndLogEx(NORMAL, " * EAS%s locked", (recv[3] & 0x02 ? "" : " not")); // EAS lock bit
|
||||||
|
PrintAndLogEx(NORMAL, " * DSFID%s locked", (recv[3] & 0x03 ? "" : " not")); // DSFID lock bit
|
||||||
|
PrintAndLogEx(NORMAL, " * Password protection configuration%s locked", (recv[3] & 0x04 ? "" : " not")); // Password protection pointer address and access conditions lock bit
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, " Features:");
|
||||||
|
PrintAndLogEx(NORMAL, " * User memory password protection%s supported", (recv[4] & 0x01 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * Counter feature%s supported", (recv[4] & 0x02 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * EAS ID%s supported by EAS ALARM command", (recv[4] & 0x03 ? "" : " not"));
|
||||||
|
easmode = (recv[4] & 0x03 ? true : false);
|
||||||
|
PrintAndLogEx(NORMAL, " * EAS password protection%s supported", (recv[4] & 0x04 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * AFI password protection%s supported", (recv[4] & 0x10 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * Extended mode%s supported by INVENTORY READ command", (recv[4] & 0x20 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * EAS selection%s supported by extended mode in INVENTORY READ command", (recv[4] & 0x40 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * READ SIGNATURE command%s supported", (recv[5] & 0x01 ? "" : " not"));
|
||||||
|
signature = (recv[5] & 0x01 ? true : false);
|
||||||
|
PrintAndLogEx(NORMAL, " * Password protection for READ SIGNATURE command%s supported", (recv[5] & 0x02 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * STAY QUIET PERSISTENT command%s supported", (recv[5] & 0x03 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * ENABLE PRIVACY command%s supported", (recv[5] & 0x10 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * DESTROY command%s supported", (recv[5] & 0x20 ? "" : " not"));
|
||||||
|
PrintAndLogEx(NORMAL, " * Additional 32 bits feature flags are%s transmitted", (recv[5] & 0x80 ? "" : " not"));
|
||||||
|
|
||||||
|
if (easmode) {
|
||||||
|
reqlen = 0;
|
||||||
|
req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
|
||||||
|
req[reqlen++] = ISO15_CMD_EASALARM;
|
||||||
|
req[reqlen++] = 0x04; // IC manufacturer code
|
||||||
|
memcpy(req + 3, uid, 8); // add UID
|
||||||
|
reqlen += 8;
|
||||||
|
|
||||||
|
AddCrc15(req, reqlen);
|
||||||
|
reqlen += 2;
|
||||||
|
|
||||||
|
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||||
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
PrintAndLogEx(WARNING, "iso15693 card select failed");
|
||||||
|
} else {
|
||||||
|
uint32_t status = resp.oldarg[0];
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
|
if (status < 2) {
|
||||||
|
PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active");
|
||||||
|
} else {
|
||||||
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
|
if (!(recv[0] & ISO15_RES_ERROR)) {
|
||||||
|
PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active.");
|
||||||
|
PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(recv + 1, 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signature) {
|
||||||
|
// Check if we can also read the signature
|
||||||
|
reqlen = 0;
|
||||||
|
req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
|
||||||
|
req[reqlen++] = ISO15_CMD_READSIGNATURE;
|
||||||
|
req[reqlen++] = 0x04; // IC manufacturer code
|
||||||
|
memcpy(req + 3, uid, 8); // add UID
|
||||||
|
reqlen += 8;
|
||||||
|
|
||||||
|
AddCrc15(req, reqlen);
|
||||||
|
reqlen += 2;
|
||||||
|
|
||||||
|
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||||
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
PrintAndLogEx(WARNING, "iso15693 card select failed");
|
||||||
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
uint32_t status = resp.oldarg[0];
|
||||||
|
|
||||||
|
if (status < 2) {
|
||||||
|
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to READ SIGNATURE command");
|
||||||
|
return PM3_EWRONGANSVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
|
return PM3_EWRONGANSVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t signature[32] = {0x00};
|
||||||
|
memcpy(signature, recv + 1, 32);
|
||||||
|
|
||||||
|
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_public_keys[0], uid, 8, signature, 32, false);
|
||||||
|
bool is_valid = (res == 0);
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(NORMAL, " Tag Signature");
|
||||||
|
PrintAndLogEx(NORMAL, " IC signature public key name : NXP ICODE SLIX2 / DNA");
|
||||||
|
PrintAndLogEx(NORMAL, " IC signature public key value : %s", sprint_hex(nxp_public_keys[0], 33));
|
||||||
|
PrintAndLogEx(NORMAL, " Elliptic curve parameters : NID_secp128r1");
|
||||||
|
PrintAndLogEx(NORMAL, " TAG IC Signature : %s", sprint_hex(signature, 32));
|
||||||
|
PrintAndLogEx(NORMAL, " Signature verification %s", (is_valid) ? _GREEN_("successful") : _RED_("failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -621,11 +827,12 @@ static int CmdHF15Info(const char *Cmd) {
|
||||||
uint8_t arg1 = 1;
|
uint8_t arg1 = 1;
|
||||||
char cmdbuf[100] = {0};
|
char cmdbuf[100] = {0};
|
||||||
char *cmd = cmdbuf;
|
char *cmd = cmdbuf;
|
||||||
|
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
||||||
|
|
||||||
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_SYSINFO))
|
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_SYSINFO))
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
AddCrc15(req, reqlen);
|
AddCrc15(req, reqlen);
|
||||||
reqlen += 2;
|
reqlen += 2;
|
||||||
|
@ -637,56 +844,69 @@ static int CmdHF15Info(const char *Cmd) {
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
PrintAndLogEx(WARNING, "iso15693 card select failed");
|
PrintAndLogEx(WARNING, "iso15693 card select failed");
|
||||||
return 1;
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
uint32_t status = resp.oldarg[0];
|
uint32_t status = resp.oldarg[0];
|
||||||
|
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command");
|
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command");
|
||||||
return 1;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
recv = resp.data.asBytes;
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
if (recv[0] & ISO15_RES_ERROR) {
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
return 3;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, recv + 2));
|
memcpy(uid, recv + 2, sizeof(uid));
|
||||||
PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(recv + 2));
|
|
||||||
PrintAndLogEx(NORMAL, " SYSINFO : %s", sprint_hex(recv, status - 2));
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid));
|
||||||
|
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(recv + 2));
|
||||||
|
PrintAndLogEx(SUCCESS, " SYSINFO : %s", sprint_hex(recv, status - 2));
|
||||||
|
|
||||||
// DSFID
|
// DSFID
|
||||||
if (recv[1] & 0x01)
|
if (recv[1] & 0x01)
|
||||||
PrintAndLogEx(NORMAL, " - DSFID supported [0x%02X]", recv[10]);
|
PrintAndLogEx(SUCCESS, " - DSFID supported [0x%02X]", recv[10]);
|
||||||
else
|
else
|
||||||
PrintAndLogEx(NORMAL, " - DSFID not supported");
|
PrintAndLogEx(SUCCESS, " - DSFID not supported");
|
||||||
|
|
||||||
// AFI
|
// AFI
|
||||||
if (recv[1] & 0x02)
|
if (recv[1] & 0x02)
|
||||||
PrintAndLogEx(NORMAL, " - AFI supported [0x%02X]", recv[11]);
|
PrintAndLogEx(SUCCESS, " - AFI supported [0x%02X]", recv[11]);
|
||||||
else
|
else
|
||||||
PrintAndLogEx(NORMAL, " - AFI not supported");
|
PrintAndLogEx(SUCCESS, " - AFI not supported");
|
||||||
|
|
||||||
// IC reference
|
// IC reference
|
||||||
if (recv[1] & 0x08)
|
if (recv[1] & 0x08)
|
||||||
PrintAndLogEx(NORMAL, " - IC reference supported [0x%02X]", recv[14]);
|
PrintAndLogEx(SUCCESS, " - IC reference supported [0x%02X]", recv[14]);
|
||||||
else
|
else
|
||||||
PrintAndLogEx(NORMAL, " - IC reference not supported");
|
PrintAndLogEx(SUCCESS, " - IC reference not supported");
|
||||||
|
|
||||||
// memory
|
// memory
|
||||||
if (recv[1] & 0x04) {
|
if (recv[1] & 0x04) {
|
||||||
PrintAndLogEx(NORMAL, " - Tag provides info on memory layout (vendor dependent)");
|
PrintAndLogEx(SUCCESS, " - Tag provides info on memory layout (vendor dependent)");
|
||||||
uint8_t blocks = recv[12] + 1;
|
uint8_t blocks = recv[12] + 1;
|
||||||
uint8_t size = (recv[13] & 0x1F);
|
uint8_t size = (recv[13] & 0x1F);
|
||||||
PrintAndLogEx(NORMAL, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks);
|
PrintAndLogEx(SUCCESS, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, " - Tag does not provide information on memory layout");
|
PrintAndLogEx(SUCCESS, " - Tag does not provide information on memory layout");
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "\n");
|
|
||||||
return 0;
|
// Check if SLIX2 and attempt to get NXP System Information
|
||||||
|
if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) {
|
||||||
|
return NxpSysInfo(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record Activity without enabling carrier
|
// Record Activity without enabling carrier
|
||||||
|
@ -697,7 +917,7 @@ static int CmdHF15Record(const char *Cmd) {
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_ISO15693_RAWADC, NULL, 0);
|
SendCommandNG(CMD_HF_ISO15693_RAWADC, NULL, 0);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHF15Reader(const char *Cmd) {
|
static int CmdHF15Reader(const char *Cmd) {
|
||||||
|
@ -705,7 +925,7 @@ static int CmdHF15Reader(const char *Cmd) {
|
||||||
if (cmdp == 'h') return usage_15_reader();
|
if (cmdp == 'h') return usage_15_reader();
|
||||||
|
|
||||||
readHF15Uid(true);
|
readHF15Uid(true);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulation is still not working very good
|
// Simulation is still not working very good
|
||||||
|
@ -717,20 +937,23 @@ static int CmdHF15Sim(const char *Cmd) {
|
||||||
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
if (param_gethex(Cmd, 0, uid, 16)) {
|
if (param_gethex(Cmd, 0, uid, 16)) {
|
||||||
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
||||||
return 0;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)));
|
PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)));
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8);
|
SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// finds the AFI (Application Family Identifier) of a card, by trying all values
|
// finds the AFI (Application Family Identifier) of a card, by trying all values
|
||||||
// (There is no standard way of reading the AFI, although some tags support this)
|
// (There is no standard way of reading the AFI, although some tags support this)
|
||||||
// helptext
|
// helptext
|
||||||
static int CmdHF15Afi(const char *Cmd) {
|
static int CmdHF15FindAfi(const char *Cmd) {
|
||||||
|
PacketResponseNG resp;
|
||||||
|
uint32_t timeout = 0;
|
||||||
|
|
||||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||||
if (cmdp == 'h') return usage_15_findafi();
|
if (cmdp == 'h') return usage_15_findafi();
|
||||||
|
|
||||||
|
@ -738,7 +961,138 @@ static int CmdHF15Afi(const char *Cmd) {
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0);
|
||||||
return 0;
|
|
||||||
|
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
timeout++;
|
||||||
|
|
||||||
|
// should be done in about 2 minutes
|
||||||
|
if (timeout > 180) {
|
||||||
|
PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting...");
|
||||||
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
return resp.status; // PM3_EOPABORTED or PM3_SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes the AFI (Application Family Identifier) of a card
|
||||||
|
static int CmdHF15WriteAfi(const char *Cmd) {
|
||||||
|
|
||||||
|
char cmdp = param_getchar(Cmd, 0);
|
||||||
|
if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_writeafi();
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
uint8_t *recv;
|
||||||
|
|
||||||
|
// arg: len, speed, recv?
|
||||||
|
// arg0 (datalen, cmd len? .arg0 == crc?)
|
||||||
|
// arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
|
||||||
|
// arg2 (recv == 1 == expect a response)
|
||||||
|
uint8_t req[PM3_CMD_DATA_SIZE] = {0};
|
||||||
|
uint16_t reqlen = 0;
|
||||||
|
uint8_t arg1 = 1;
|
||||||
|
int afinum;
|
||||||
|
char cmdbuf[100] = {0};
|
||||||
|
char *cmd = cmdbuf;
|
||||||
|
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
||||||
|
|
||||||
|
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITEAFI))
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
|
req[0] |= ISO15_REQ_OPTION; // Since we are writing
|
||||||
|
|
||||||
|
afinum = strtol(cmd, NULL, 0);
|
||||||
|
|
||||||
|
req[reqlen++] = (uint8_t)afinum;
|
||||||
|
|
||||||
|
AddCrc15(req, reqlen);
|
||||||
|
reqlen += 2;
|
||||||
|
|
||||||
|
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||||
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
PrintAndLogEx(ERR, "iso15693 card select failed");
|
||||||
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
|
return PM3_EWRONGANSVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, "Wrote AFI 0x%02X", afinum);
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes the DSFID (Data Storage Format Identifier) of a card
|
||||||
|
static int CmdHF15WriteDsfid(const char *Cmd) {
|
||||||
|
|
||||||
|
char cmdp = param_getchar(Cmd, 0);
|
||||||
|
if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_writedsfid();
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
uint8_t *recv;
|
||||||
|
|
||||||
|
// arg: len, speed, recv?
|
||||||
|
// arg0 (datalen, cmd len? .arg0 == crc?)
|
||||||
|
// arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
|
||||||
|
// arg2 (recv == 1 == expect a response)
|
||||||
|
uint8_t req[PM3_CMD_DATA_SIZE] = {0};
|
||||||
|
uint16_t reqlen = 0;
|
||||||
|
uint8_t arg1 = 1;
|
||||||
|
int dsfidnum;
|
||||||
|
char cmdbuf[100] = {0};
|
||||||
|
char *cmd = cmdbuf;
|
||||||
|
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
||||||
|
|
||||||
|
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITEDSFID))
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
|
req[0] |= ISO15_REQ_OPTION; // Since we are writing
|
||||||
|
|
||||||
|
dsfidnum = strtol(cmd, NULL, 0);
|
||||||
|
|
||||||
|
req[reqlen++] = (uint8_t)dsfidnum;
|
||||||
|
|
||||||
|
AddCrc15(req, reqlen);
|
||||||
|
reqlen += 2;
|
||||||
|
|
||||||
|
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||||
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
PrintAndLogEx(ERR, "iso15693 card select failed");
|
||||||
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
|
return PM3_EWRONGANSVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, "Wrote DSFID 0x%02X", dsfidnum);
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -777,7 +1131,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
|
|
||||||
if (!getUID(uid)) {
|
if (!getUID(uid)) {
|
||||||
PrintAndLogEx(WARNING, "No tag found.");
|
PrintAndLogEx(WARNING, "No tag found.");
|
||||||
return 1;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileNameLen < 1) {
|
if (fileNameLen < 1) {
|
||||||
|
@ -789,7 +1143,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
}
|
}
|
||||||
// detect blocksize from card :)
|
// detect blocksize from card :)
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid));
|
PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid));
|
||||||
|
|
||||||
int blocknum = 0;
|
int blocknum = 0;
|
||||||
uint8_t *recv = NULL;
|
uint8_t *recv = NULL;
|
||||||
|
@ -847,8 +1201,10 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "\n");
|
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "block# | data |lck| ascii");
|
PrintAndLogEx(NORMAL, "block# | data |lck| ascii");
|
||||||
PrintAndLogEx(NORMAL, "---------+--------------+---+----------");
|
PrintAndLogEx(NORMAL, "---------+--------------+---+----------");
|
||||||
for (int i = 0; i < blocknum; i++) {
|
for (int i = 0; i < blocknum; i++) {
|
||||||
|
@ -871,8 +1227,7 @@ static int CmdHF15List(const char *Cmd) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Record Activity without enabling carrier
|
// Record Activity without enabling carrier
|
||||||
static int CmdHF15Sniff(const char *Cmd)
|
static int CmdHF15Sniff(const char *Cmd) {
|
||||||
{
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0);
|
SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -886,7 +1241,7 @@ static int CmdHF15Raw(const char *Cmd) {
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
int reply = 1, fast = 1, i = 0;
|
int reply = 1, fast = 1, i = 0;
|
||||||
bool crc = false;
|
bool crc = false, leaveSignalON = false;
|
||||||
char buf[5] = "";
|
char buf[5] = "";
|
||||||
uint8_t data[100];
|
uint8_t data[100];
|
||||||
uint32_t datalen = 0, temp;
|
uint32_t datalen = 0, temp;
|
||||||
|
@ -909,9 +1264,13 @@ static int CmdHF15Raw(const char *Cmd) {
|
||||||
case 'C':
|
case 'C':
|
||||||
crc = true;
|
crc = true;
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
case 'P':
|
||||||
|
leaveSignalON = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(WARNING, "Invalid option");
|
PrintAndLogEx(WARNING, "Invalid option");
|
||||||
return 0;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
i += 2;
|
i += 2;
|
||||||
continue;
|
continue;
|
||||||
|
@ -932,7 +1291,7 @@ static int CmdHF15Raw(const char *Cmd) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(WARNING, "Invalid char on input");
|
PrintAndLogEx(WARNING, "Invalid char on input");
|
||||||
return 0;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crc) {
|
if (crc) {
|
||||||
|
@ -946,12 +1305,16 @@ static int CmdHF15Raw(const char *Cmd) {
|
||||||
if (reply) {
|
if (reply) {
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
uint8_t len = resp.oldarg[0];
|
uint8_t len = resp.oldarg[0];
|
||||||
PrintAndLogEx(NORMAL, "received %i octets", len);
|
PrintAndLogEx(INFO, "received %i octets", len);
|
||||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len));
|
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, len));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!leaveSignalON)
|
||||||
|
DropField();
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,7 +1338,7 @@ static int CmdHF15Readmulti(const char *Cmd) {
|
||||||
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
||||||
|
|
||||||
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READMULTI))
|
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READMULTI))
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
// add OPTION flag, in order to get lock-info
|
// add OPTION flag, in order to get lock-info
|
||||||
req[0] |= ISO15_REQ_OPTION;
|
req[0] |= ISO15_REQ_OPTION;
|
||||||
|
@ -1000,25 +1363,28 @@ static int CmdHF15Readmulti(const char *Cmd) {
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 card select failed");
|
PrintAndLogEx(FAILED, "iso15693 card select failed");
|
||||||
return 1;
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
uint32_t status = resp.oldarg[0];
|
uint32_t status = resp.oldarg[0];
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 card select failed");
|
PrintAndLogEx(FAILED, "iso15693 card select failed");
|
||||||
return 1;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
recv = resp.data.asBytes;
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
if (!CheckCrc15(recv, status)) {
|
if (!CheckCrc15(recv, status)) {
|
||||||
PrintAndLogEx(FAILED, "CRC failed");
|
PrintAndLogEx(FAILED, "CRC failed");
|
||||||
return 2;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv[0] & ISO15_RES_ERROR) {
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
return 3;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start = 1; // skip status byte
|
int start = 1; // skip status byte
|
||||||
|
@ -1061,7 +1427,7 @@ static int CmdHF15Read(const char *Cmd) {
|
||||||
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
||||||
|
|
||||||
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READ))
|
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READ))
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
// add OPTION flag, in order to get lock-info
|
// add OPTION flag, in order to get lock-info
|
||||||
req[0] |= ISO15_REQ_OPTION;
|
req[0] |= ISO15_REQ_OPTION;
|
||||||
|
@ -1077,26 +1443,29 @@ static int CmdHF15Read(const char *Cmd) {
|
||||||
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
PrintAndLogEx(NORMAL, "iso15693 card select failed");
|
PrintAndLogEx(ERR, "iso15693 card select failed");
|
||||||
return 1;
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
uint32_t status = resp.oldarg[0];
|
uint32_t status = resp.oldarg[0];
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(NORMAL, "iso15693 card select failed");
|
PrintAndLogEx(ERR, "iso15693 card select failed");
|
||||||
return 1;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
recv = resp.data.asBytes;
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
if (!CheckCrc15(recv, status)) {
|
if (!CheckCrc15(recv, status)) {
|
||||||
PrintAndLogEx(NORMAL, "CRC failed");
|
PrintAndLogEx(ERR, "CRC failed");
|
||||||
return 2;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv[0] & ISO15_RES_ERROR) {
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
return 3;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print response
|
// print response
|
||||||
|
@ -1130,7 +1499,7 @@ static int CmdHF15Write(const char *Cmd) {
|
||||||
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
strncpy(cmd, Cmd, sizeof(cmdbuf) - 1);
|
||||||
|
|
||||||
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITE))
|
if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITE))
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
// *cmd -> page num ; *cmd2 -> data
|
// *cmd -> page num ; *cmd2 -> data
|
||||||
cmd2 = cmd;
|
cmd2 = cmd;
|
||||||
|
@ -1154,32 +1523,35 @@ static int CmdHF15Write(const char *Cmd) {
|
||||||
AddCrc15(req, reqlen);
|
AddCrc15(req, reqlen);
|
||||||
reqlen += 2;
|
reqlen += 2;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum);
|
PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum);
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway");
|
PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway");
|
||||||
return 1;
|
DropField();
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
uint32_t status = resp.oldarg[0];
|
uint32_t status = resp.oldarg[0];
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 card select failed");
|
PrintAndLogEx(FAILED, "iso15693 card select failed");
|
||||||
return 1;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
recv = resp.data.asBytes;
|
recv = resp.data.asBytes;
|
||||||
|
|
||||||
if (!CheckCrc15(recv, status)) {
|
if (!CheckCrc15(recv, status)) {
|
||||||
PrintAndLogEx(FAILED, "CRC failed");
|
PrintAndLogEx(FAILED, "CRC failed");
|
||||||
return 2;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv[0] & ISO15_RES_ERROR) {
|
if (recv[0] & ISO15_RES_ERROR) {
|
||||||
PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
|
||||||
return 3;
|
return PM3_EWRONGANSVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "OK");
|
PrintAndLogEx(NORMAL, "OK");
|
||||||
|
@ -1250,13 +1622,13 @@ static int CmdHF15Restore(const char *Cmd) {
|
||||||
|
|
||||||
if ((f = fopen(filename, "rb")) == NULL) {
|
if ((f = fopen(filename, "rb")) == NULL) {
|
||||||
PrintAndLogEx(WARNING, "Could not find file %s", filename);
|
PrintAndLogEx(WARNING, "Could not find file %s", filename);
|
||||||
return 2;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getUID(uid)) {
|
if (!getUID(uid)) {
|
||||||
PrintAndLogEx(WARNING, "No tag found");
|
PrintAndLogEx(WARNING, "No tag found");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 3;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Restoring data blocks.");
|
PrintAndLogEx(INFO, "Restoring data blocks.");
|
||||||
|
@ -1274,7 +1646,7 @@ static int CmdHF15Restore(const char *Cmd) {
|
||||||
} else if (bytes_read != blocksize) {
|
} else if (bytes_read != blocksize) {
|
||||||
PrintAndLogEx(ERR, "File reading error (%s), %zu bytes read instead of %zu bytes.", filename, bytes_read, blocksize);
|
PrintAndLogEx(ERR, "File reading error (%s), %zu bytes read instead of %zu bytes.", filename, bytes_read, blocksize);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 2;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < blocksize; j++)
|
for (int j = 0; j < blocksize; j++)
|
||||||
|
@ -1322,22 +1694,23 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
||||||
|
|
||||||
if (param_gethex(Cmd, 0, uid, 16)) {
|
if (param_gethex(Cmd, 0, uid, 16)) {
|
||||||
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid[0] != 0xe0) {
|
if (uid[0] != 0xe0) {
|
||||||
PrintAndLogEx(WARNING, "UID must begin with the byte " _YELLOW_("E0"));
|
PrintAndLogEx(WARNING, "UID must begin with the byte " _YELLOW_("E0"));
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "new UID | %s", sprint_hex(uid, sizeof(uid)));
|
PrintAndLogEx(SUCCESS, "Input new UID | %s", sprint_hex(uid, sizeof(uid)));
|
||||||
PrintAndLogEx(NORMAL, "Using backdoor Magic tag function");
|
|
||||||
|
|
||||||
if (!getUID(oldUid)) {
|
if (!getUID(oldUid)) {
|
||||||
PrintAndLogEx(FAILED, "Can't get old UID.");
|
PrintAndLogEx(FAILED, "Can't get old/current UID.");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Using backdoor magic tag function");
|
||||||
|
|
||||||
// Command 1 : 02213E00000000
|
// Command 1 : 02213E00000000
|
||||||
data[0][0] = 0x02;
|
data[0][0] = 0x02;
|
||||||
data[0][1] = 0x21;
|
data[0][1] = 0x21;
|
||||||
|
@ -1383,8 +1756,8 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
||||||
if (reply) {
|
if (reply) {
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
uint8_t len = resp.oldarg[0];
|
uint8_t len = resp.oldarg[0];
|
||||||
PrintAndLogEx(NORMAL, "received %i octets", len);
|
PrintAndLogEx(INFO, "received %i octets", len);
|
||||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len));
|
PrintAndLogEx(INFO, "%s", sprint_hex(resp.data.asBytes, len));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
}
|
}
|
||||||
|
@ -1396,18 +1769,23 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
if (memcmp(newUid, uid, 8) != 0) {
|
||||||
PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]);
|
PrintAndLogEx(FAILED, "Setting UID on tag failed.");
|
||||||
PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]);
|
return PM3_ESOFT;
|
||||||
|
} else {
|
||||||
return PM3_SUCCESS;
|
PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]);
|
||||||
|
PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHF15Help, AlwaysAvailable, "This help"},
|
{"help", CmdHF15Help, AlwaysAvailable, "This help"},
|
||||||
{"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"},
|
{"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"},
|
||||||
{"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"},
|
{"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"},
|
||||||
{"findafi", CmdHF15Afi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"},
|
{"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"},
|
||||||
|
{"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"},
|
||||||
|
{"writedsfid", CmdHF15WriteDsfid, IfPm3Iso15693, "Writes the DSFID on an ISO15693 tag"},
|
||||||
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
|
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
|
||||||
// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
|
// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
|
||||||
{"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"},
|
{"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"},
|
||||||
|
@ -1436,14 +1814,14 @@ int CmdHF15(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// used with 'hf search'
|
// used with 'hf search'
|
||||||
int readHF15Uid(bool verbose) {
|
bool readHF15Uid(bool verbose) {
|
||||||
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
if (!getUID(uid)) {
|
if (!getUID(uid)) {
|
||||||
if (verbose) PrintAndLogEx(WARNING, "No tag found.");
|
if (verbose) PrintAndLogEx(WARNING, "No tag found.");
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, uid));
|
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid));
|
||||||
PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(uid));
|
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(uid));
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,6 @@
|
||||||
|
|
||||||
int CmdHF15(const char *Cmd);
|
int CmdHF15(const char *Cmd);
|
||||||
|
|
||||||
int readHF15Uid(bool verbose);
|
bool readHF15Uid(bool verbose);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "cmdparser.h" // command_t
|
#include "cmdparser.h" // command_t
|
||||||
#include "commonutil.h" // ARRAYLEN
|
#include "commonutil.h" // ARRAYLEN
|
||||||
#include "comms.h" // clearCommandBuffer
|
#include "comms.h" // clearCommandBuffer
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "util_posix.h"
|
#include "util_posix.h"
|
||||||
|
@ -38,8 +38,8 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) {
|
||||||
m = m > 0 ? m : 1;
|
m = m > 0 ? m : 1;
|
||||||
n = n > 0 ? n : 1;
|
n = n > 0 ? n : 1;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Collecting %u %u byte nonces", n, m);
|
PrintAndLogEx(SUCCESS, "Collecting %u %u byte nonces", n, m);
|
||||||
PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock() / 1000);
|
PrintAndLogEx(SUCCESS, "Start: %" PRIu64, msclock() / 1000);
|
||||||
// repeat n times
|
// repeat n times
|
||||||
for (uint32_t i = 0; i < n; i++) {
|
for (uint32_t i = 0; i < n; i++) {
|
||||||
// execute PACE
|
// execute PACE
|
||||||
|
@ -58,15 +58,15 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) {
|
||||||
sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]);
|
sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]);
|
||||||
}
|
}
|
||||||
// print nonce
|
// print nonce
|
||||||
PrintAndLogEx(NORMAL, "Length: %zu, Nonce: %s", nonce_length, nonce);
|
PrintAndLogEx(SUCCESS, "Length: %zu, Nonce: %s", nonce_length, nonce);
|
||||||
free(nonce);
|
free(nonce);
|
||||||
}
|
}
|
||||||
if (i < n - 1) {
|
if (i < n - 1) {
|
||||||
sleep(d);
|
sleep(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock() / 1000);
|
PrintAndLogEx(SUCCESS, "End: %" PRIu64, msclock() / 1000);
|
||||||
return 1;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform the PACE protocol by replaying APDUs
|
// perform the PACE protocol by replaying APDUs
|
||||||
|
@ -98,9 +98,9 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (scan_return < 1) {
|
if (scan_return < 1) {
|
||||||
PrintAndLogEx(NORMAL, (char *)usage_msg);
|
PrintAndLogEx(INFO, (char *)usage_msg);
|
||||||
PrintAndLogEx(WARNING, "Not enough APDUs! Try again!");
|
PrintAndLogEx(WARNING, "Not enough APDUs! Try again!");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
skip += skip_add;
|
skip += skip_add;
|
||||||
apdu_lengths[i]++;
|
apdu_lengths[i]++;
|
||||||
|
@ -110,8 +110,8 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
|
||||||
if (Cmd[skip] == '\0') {
|
if (Cmd[skip] == '\0') {
|
||||||
if (i < ARRAYLEN(apdu_lengths) - 1) {
|
if (i < ARRAYLEN(apdu_lengths) - 1) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, (char *)usage_msg);
|
PrintAndLogEx(INFO, (char *)usage_msg);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
|
||||||
WaitForResponse(CMD_ACK, &resp);
|
WaitForResponse(CMD_ACK, &resp);
|
||||||
if (resp.oldarg[0] != 0) {
|
if (resp.oldarg[0] != 0) {
|
||||||
PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j);
|
PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j);
|
||||||
return 0;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,22 +156,22 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
|
||||||
SendCommandMIX(CMD_HF_EPA_REPLAY, 0, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_EPA_REPLAY, 0, 0, 0, NULL, 0);
|
||||||
WaitForResponse(CMD_ACK, &resp);
|
WaitForResponse(CMD_ACK, &resp);
|
||||||
if (resp.oldarg[0] != 0) {
|
if (resp.oldarg[0] != 0) {
|
||||||
PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]);
|
PrintAndLogEx(SUCCESS, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]);
|
||||||
PrintAndLogEx(NORMAL, "Measured times:");
|
PrintAndLogEx(SUCCESS, "Measured times:");
|
||||||
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]);
|
PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]);
|
||||||
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]);
|
PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]);
|
||||||
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]);
|
PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]);
|
||||||
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
|
PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
|
||||||
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
|
PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, "PACE replay successful!");
|
PrintAndLogEx(SUCCESS, "PACE replay successful!");
|
||||||
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]);
|
PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]);
|
||||||
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]);
|
PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]);
|
||||||
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]);
|
PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]);
|
||||||
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
|
PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
|
||||||
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
|
PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
|
||||||
}
|
}
|
||||||
return 1;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
|
@ -184,7 +184,7 @@ static command_t CommandTable[] = {
|
||||||
static int CmdHelp(const char *Cmd) {
|
static int CmdHelp(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
CmdsHelp(CommandTable);
|
CmdsHelp(CommandTable);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdHFEPA(const char *Cmd) {
|
int CmdHFEPA(const char *Cmd) {
|
||||||
|
|
|
@ -320,12 +320,12 @@ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose)
|
||||||
if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) {
|
||||||
uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff);
|
uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(NORMAL, "Client Received %i octets", len);
|
PrintAndLogEx(SUCCESS, "Client Received %i octets", len);
|
||||||
if (!len || len < 2) {
|
if (!len || len < 2) {
|
||||||
PrintAndLogEx(ERR, "Could not receive data correctly!");
|
PrintAndLogEx(ERR, "Could not receive data correctly!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len));
|
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp->data.asBytes, len));
|
||||||
if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) {
|
if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) {
|
||||||
PrintAndLogEx(WARNING, "Wrong or no CRC bytes");
|
PrintAndLogEx(WARNING, "Wrong or no CRC bytes");
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,7 @@ static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *dat
|
||||||
uint16_t numbits = 0;
|
uint16_t numbits = 0;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(NORMAL, "Send RAW COMMAND - Frame: %s", sprint_hex(data, datalen));
|
PrintAndLogEx(INFO, "Send raw command - Frame: %s", sprint_hex(data, datalen));
|
||||||
}
|
}
|
||||||
SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen);
|
SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen);
|
||||||
}
|
}
|
||||||
|
@ -438,11 +438,11 @@ static void print_rd_noEncrpytion_response(felica_read_without_encryption_respon
|
||||||
char bl_element_number[4];
|
char bl_element_number[4];
|
||||||
temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number));
|
temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number));
|
||||||
strcpy(bl_element_number, temp);
|
strcpy(bl_element_number, temp);
|
||||||
PrintAndLogEx(NORMAL, "\t%s\t| %s ", bl_element_number, bl_data);
|
PrintAndLogEx(INFO, "\t%s\t| %s ", bl_element_number, bl_data);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm)));
|
PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1)));
|
PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1)));
|
PrintAndLogEx(SUCCESS, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +454,7 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (datalen > 0) {
|
if (datalen > 0) {
|
||||||
if (!waitCmdFelica(0, &resp, 1)) {
|
if (!waitCmdFelica(0, &resp, 1)) {
|
||||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
PrintAndLogEx(ERR, "\nGot no response from card");
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
}
|
}
|
||||||
felica_request_service_response_t rqs_response;
|
felica_request_service_response_t rqs_response;
|
||||||
|
@ -462,9 +462,9 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve
|
||||||
|
|
||||||
if (rqs_response.frame_response.IDm[0] != 0) {
|
if (rqs_response.frame_response.IDm[0] != 0) {
|
||||||
PrintAndLogEx(SUCCESS, "\nGot Service Response:");
|
PrintAndLogEx(SUCCESS, "\nGot Service Response:");
|
||||||
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm)));
|
PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm)));
|
||||||
PrintAndLogEx(NORMAL, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number)));
|
PrintAndLogEx(SUCCESS, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number)));
|
||||||
PrintAndLogEx(NORMAL, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions)));
|
PrintAndLogEx(SUCCESS, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions)));
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -484,7 +484,7 @@ int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver
|
||||||
clear_and_send_command(flags, datalen, data, verbose);
|
clear_and_send_command(flags, datalen, data, verbose);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!waitCmdFelica(0, &resp, verbose)) {
|
if (!waitCmdFelica(0, &resp, verbose)) {
|
||||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
PrintAndLogEx(ERR, "\nGot no response from card");
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
} else {
|
} else {
|
||||||
memcpy(rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t));
|
memcpy(rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t));
|
||||||
|
@ -522,7 +522,7 @@ int send_wr_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver
|
||||||
clear_and_send_command(flags, datalen, data, verbose);
|
clear_and_send_command(flags, datalen, data, verbose);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!waitCmdFelica(0, &resp, verbose)) {
|
if (!waitCmdFelica(0, &resp, verbose)) {
|
||||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
PrintAndLogEx(ERR, "\nGot no response from card");
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
} else {
|
} else {
|
||||||
memcpy(wr_noCry_resp, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t));
|
memcpy(wr_noCry_resp, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t));
|
||||||
|
@ -548,8 +548,7 @@ static int CmdHFFelicaAuthentication1(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_authentication1();
|
return usage_hf_felica_authentication1();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -656,8 +655,7 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_write_without_encryption();
|
return usage_hf_felica_write_without_encryption();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -696,9 +694,9 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) {
|
||||||
datalen += 2;
|
datalen += 2;
|
||||||
felica_status_response_t wr_noCry_resp;
|
felica_status_response_t wr_noCry_resp;
|
||||||
if (send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS) {
|
if (send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm)));
|
PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1)));
|
PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2)));
|
PrintAndLogEx(SUCCESS, "Status Flag2: %s\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2)));
|
||||||
if (wr_noCry_resp.status_flags.status_flag1[0] == 0x00 && wr_noCry_resp.status_flags.status_flag2[0] == 0x00) {
|
if (wr_noCry_resp.status_flags.status_flag1[0] == 0x00 && wr_noCry_resp.status_flags.status_flag2[0] == 0x00) {
|
||||||
PrintAndLogEx(SUCCESS, "Writing data successful!\n");
|
PrintAndLogEx(SUCCESS, "Writing data successful!\n");
|
||||||
} else {
|
} else {
|
||||||
|
@ -727,8 +725,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_read_without_encryption();
|
return usage_hf_felica_read_without_encryption();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -781,7 +778,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
|
||||||
if (long_block_numbers) {
|
if (long_block_numbers) {
|
||||||
last_block_number = 0xFFFF;
|
last_block_number = 0xFFFF;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "Block Element\t| Data ");
|
PrintAndLogEx(INFO, "Block Element\t| Data ");
|
||||||
for (int i = 0x00; i < last_block_number; i++) {
|
for (int i = 0x00; i < last_block_number; i++) {
|
||||||
data[15] = i;
|
data[15] = i;
|
||||||
AddCrc(data, datalen);
|
AddCrc(data, datalen);
|
||||||
|
@ -803,7 +800,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
|
||||||
datalen += 2;
|
datalen += 2;
|
||||||
felica_read_without_encryption_response_t rd_noCry_resp;
|
felica_read_without_encryption_response_t rd_noCry_resp;
|
||||||
if (send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS) {
|
if (send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(NORMAL, "Block Element\t| Data ");
|
PrintAndLogEx(INFO, "Block Element\t| Data ");
|
||||||
print_rd_noEncrpytion_response(&rd_noCry_resp);
|
print_rd_noEncrpytion_response(&rd_noCry_resp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -825,8 +822,7 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_request_response();
|
return usage_hf_felica_request_response();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -856,15 +852,15 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) {
|
||||||
clear_and_send_command(flags, datalen, data, 0);
|
clear_and_send_command(flags, datalen, data, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!waitCmdFelica(0, &resp, 1)) {
|
if (!waitCmdFelica(0, &resp, 1)) {
|
||||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
PrintAndLogEx(ERR, "\nGot no response from card");
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
} else {
|
} else {
|
||||||
felica_request_request_response_t rq_response;
|
felica_request_request_response_t rq_response;
|
||||||
memcpy(&rq_response, (felica_request_request_response_t *)resp.data.asBytes, sizeof(felica_request_request_response_t));
|
memcpy(&rq_response, (felica_request_request_response_t *)resp.data.asBytes, sizeof(felica_request_request_response_t));
|
||||||
if (rq_response.frame_response.IDm[0] != 0) {
|
if (rq_response.frame_response.IDm[0] != 0) {
|
||||||
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
||||||
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm)));
|
PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm)));
|
||||||
PrintAndLogEx(NORMAL, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode)));
|
PrintAndLogEx(SUCCESS, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -887,8 +883,7 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_request_specification_version();
|
return usage_hf_felica_request_specification_version();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -931,24 +926,24 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) {
|
||||||
clear_and_send_command(flags, datalen, data, 0);
|
clear_and_send_command(flags, datalen, data, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!waitCmdFelica(0, &resp, 1)) {
|
if (!waitCmdFelica(0, &resp, 1)) {
|
||||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
PrintAndLogEx(ERR, "\nGot no response from card");
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
} else {
|
} else {
|
||||||
felica_request_spec_response_t spec_response;
|
felica_request_spec_response_t spec_response;
|
||||||
memcpy(&spec_response, (felica_request_spec_response_t *)resp.data.asBytes, sizeof(felica_request_spec_response_t));
|
memcpy(&spec_response, (felica_request_spec_response_t *)resp.data.asBytes, sizeof(felica_request_spec_response_t));
|
||||||
if (spec_response.frame_response.IDm[0] != 0) {
|
if (spec_response.frame_response.IDm[0] != 0) {
|
||||||
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
||||||
PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm)));
|
PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(spec_response.status_flags.status_flag1, sizeof(spec_response.status_flags.status_flag1)));
|
PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(spec_response.status_flags.status_flag1, sizeof(spec_response.status_flags.status_flag1)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(spec_response.status_flags.status_flag2, sizeof(spec_response.status_flags.status_flag2)));
|
PrintAndLogEx(SUCCESS, "Status Flag2: %s", sprint_hex(spec_response.status_flags.status_flag2, sizeof(spec_response.status_flags.status_flag2)));
|
||||||
if (spec_response.status_flags.status_flag1[0] == 0x00) {
|
if (spec_response.status_flags.status_flag1[0] == 0x00) {
|
||||||
PrintAndLogEx(NORMAL, "Format Version: %s", sprint_hex(spec_response.format_version, sizeof(spec_response.format_version)));
|
PrintAndLogEx(SUCCESS, "Format Version: %s", sprint_hex(spec_response.format_version, sizeof(spec_response.format_version)));
|
||||||
PrintAndLogEx(NORMAL, "Basic Version: %s", sprint_hex(spec_response.basic_version, sizeof(spec_response.basic_version)));
|
PrintAndLogEx(SUCCESS, "Basic Version: %s", sprint_hex(spec_response.basic_version, sizeof(spec_response.basic_version)));
|
||||||
PrintAndLogEx(NORMAL, "Number of Option: %s", sprint_hex(spec_response.number_of_option, sizeof(spec_response.number_of_option)));
|
PrintAndLogEx(SUCCESS, "Number of Option: %s", sprint_hex(spec_response.number_of_option, sizeof(spec_response.number_of_option)));
|
||||||
if (spec_response.number_of_option[0] == 0x01) {
|
if (spec_response.number_of_option[0] == 0x01) {
|
||||||
PrintAndLogEx(NORMAL, "Option Version List:");
|
PrintAndLogEx(SUCCESS, "Option Version List:");
|
||||||
for (uint8_t i = 0; i < spec_response.number_of_option[0]; i++) {
|
for (uint8_t i = 0; i < spec_response.number_of_option[0]; i++) {
|
||||||
PrintAndLogEx(NORMAL, " - %s", sprint_hex(spec_response.option_version_list + i * 2, sizeof(uint8_t) * 2));
|
PrintAndLogEx(SUCCESS, " - %s", sprint_hex(spec_response.option_version_list + i * 2, sizeof(uint8_t) * 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -974,8 +969,7 @@ static int CmdHFFelicaResetMode(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_reset_mode();
|
return usage_hf_felica_reset_mode();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -1018,16 +1012,16 @@ static int CmdHFFelicaResetMode(const char *Cmd) {
|
||||||
clear_and_send_command(flags, datalen, data, 0);
|
clear_and_send_command(flags, datalen, data, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!waitCmdFelica(0, &resp, 1)) {
|
if (!waitCmdFelica(0, &resp, 1)) {
|
||||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
PrintAndLogEx(ERR, "\nGot no response from card");
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
} else {
|
} else {
|
||||||
felica_status_response_t reset_mode_response;
|
felica_status_response_t reset_mode_response;
|
||||||
memcpy(&reset_mode_response, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t));
|
memcpy(&reset_mode_response, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t));
|
||||||
if (reset_mode_response.frame_response.IDm[0] != 0) {
|
if (reset_mode_response.frame_response.IDm[0] != 0) {
|
||||||
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
||||||
PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(reset_mode_response.frame_response.IDm, sizeof(reset_mode_response.frame_response.IDm)));
|
PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(reset_mode_response.frame_response.IDm, sizeof(reset_mode_response.frame_response.IDm)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(reset_mode_response.status_flags.status_flag1, sizeof(reset_mode_response.status_flags.status_flag1)));
|
PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(reset_mode_response.status_flags.status_flag1, sizeof(reset_mode_response.status_flags.status_flag1)));
|
||||||
PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2)));
|
PrintAndLogEx(SUCCESS, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -1048,8 +1042,7 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_request_system_code();
|
return usage_hf_felica_request_system_code();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -1079,18 +1072,18 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
|
||||||
clear_and_send_command(flags, datalen, data, 0);
|
clear_and_send_command(flags, datalen, data, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!waitCmdFelica(0, &resp, 1)) {
|
if (!waitCmdFelica(0, &resp, 1)) {
|
||||||
PrintAndLogEx(ERR, "\nGot no Response from card");
|
PrintAndLogEx(ERR, "\nGot no response from card");
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
} else {
|
} else {
|
||||||
felica_syscode_response_t rq_syscode_response;
|
felica_syscode_response_t rq_syscode_response;
|
||||||
memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t));
|
memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t));
|
||||||
if (rq_syscode_response.frame_response.IDm[0] != 0) {
|
if (rq_syscode_response.frame_response.IDm[0] != 0) {
|
||||||
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
|
||||||
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm)));
|
PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm)));
|
||||||
PrintAndLogEx(NORMAL, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems)));
|
PrintAndLogEx(SUCCESS, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems)));
|
||||||
PrintAndLogEx(NORMAL, " - System Codes: enumerated in ascending order starting from System 0.");
|
PrintAndLogEx(SUCCESS, " - System Codes: enumerated in ascending order starting from System 0.");
|
||||||
for (uint8_t i = 0; i < rq_syscode_response.number_of_systems[0]; i++) {
|
for (uint8_t i = 0; i < rq_syscode_response.number_of_systems[0]; i++) {
|
||||||
PrintAndLogEx(NORMAL, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, sizeof(uint8_t) * 2));
|
PrintAndLogEx(SUCCESS, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, sizeof(uint8_t) * 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1114,8 +1107,7 @@ static int CmdHFFelicaRequestService(const char *Cmd) {
|
||||||
strip_cmds(Cmd);
|
strip_cmds(Cmd);
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_request_service();
|
return usage_hf_felica_request_service();
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -1151,7 +1143,7 @@ static int CmdHFFelicaRequestService(const char *Cmd) {
|
||||||
if (param_getlength(Cmd, paramCount) == 4) {
|
if (param_getlength(Cmd, paramCount) == 4) {
|
||||||
param_gethex(Cmd, paramCount++, data + 11, 4);
|
param_gethex(Cmd, paramCount++, data + 11, 4);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "Incorrect Parameter length!");
|
PrintAndLogEx(ERR, "Incorrect parameter length!");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,7 +1178,8 @@ static int CmdHFFelicaRequestService(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFFelicaNotImplementedYet(const char *Cmd) {
|
static int CmdHFFelicaNotImplementedYet(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "Feature not implemented Yet!");
|
PrintAndLogEx(INFO, "Feature not implemented yet.");
|
||||||
|
PrintAndLogEx(INFO, "Feel free to contribute!");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,12 +1191,10 @@ static int CmdHFFelicaSniff(const char *Cmd) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'h':
|
|
||||||
case 'H':
|
case 'H':
|
||||||
return usage_hf_felica_sniff();
|
return usage_hf_felica_sniff();
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
|
||||||
paramCount++;
|
paramCount++;
|
||||||
if (param_getlength(Cmd, paramCount) < 5) {
|
if (param_getlength(Cmd, paramCount) < 5) {
|
||||||
samples2skip = param_get32ex(Cmd, paramCount++, 0, 10);
|
samples2skip = param_get32ex(Cmd, paramCount++, 0, 10);
|
||||||
|
@ -1213,7 +1204,6 @@ static int CmdHFFelicaSniff(const char *Cmd) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
case 'T':
|
|
||||||
paramCount++;
|
paramCount++;
|
||||||
if (param_getlength(Cmd, paramCount) < 5) {
|
if (param_getlength(Cmd, paramCount) < 5) {
|
||||||
triggers2skip = param_get32ex(Cmd, paramCount++, 0, 10);
|
triggers2skip = param_get32ex(Cmd, paramCount++, 0, 10);
|
||||||
|
@ -1259,7 +1249,7 @@ static int CmdHFFelicaSimLite(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printSep() {
|
static void printSep() {
|
||||||
PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------");
|
PrintAndLogEx(INFO, "------------------------------------------------------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) {
|
static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) {
|
||||||
|
@ -1495,8 +1485,7 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
|
||||||
while (Cmd[i] != '\0') {
|
while (Cmd[i] != '\0') {
|
||||||
if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; }
|
if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; }
|
||||||
if (Cmd[i] == '-') {
|
if (Cmd[i] == '-') {
|
||||||
switch (Cmd[i + 1]) {
|
switch (tolower(Cmd[i + 1])) {
|
||||||
case 'H':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_felica_raw();
|
return usage_hf_felica_raw();
|
||||||
case 'r':
|
case 'r':
|
||||||
|
@ -1540,7 +1529,7 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
|
||||||
*buf = 0;
|
*buf = 0;
|
||||||
if (++datalen >= sizeof(data)) {
|
if (++datalen >= sizeof(data)) {
|
||||||
if (crc)
|
if (crc)
|
||||||
PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data");
|
PrintAndLogEx(WARNING, "Buffer is full, we can't add CRC to your data");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1574,12 +1563,12 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
|
||||||
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
PrintAndLogEx(NORMAL, "Data: %s", sprint_hex(data, datalen));
|
PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(data, datalen));
|
||||||
SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen);
|
SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen);
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
if (active_select) {
|
if (active_select) {
|
||||||
PrintAndLogEx(NORMAL, "Active select wait for FeliCa.");
|
PrintAndLogEx(SUCCESS, "Active select wait for FeliCa.");
|
||||||
PacketResponseNG resp_IDm;
|
PacketResponseNG resp_IDm;
|
||||||
waitCmdFelica(1, &resp_IDm, 1);
|
waitCmdFelica(1, &resp_IDm, 1);
|
||||||
}
|
}
|
||||||
|
@ -1625,15 +1614,15 @@ int readFelicaUid(bool verbose) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, "FeliCa tag info");
|
PrintAndLogEx(SUCCESS, "FeliCa tag info");
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm)));
|
PrintAndLogEx(SUCCESS, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm)));
|
||||||
PrintAndLogEx(NORMAL, " - CODE %s", sprint_hex(card.code, sizeof(card.code)));
|
PrintAndLogEx(SUCCESS, " - CODE %s", sprint_hex(card.code, sizeof(card.code)));
|
||||||
PrintAndLogEx(NORMAL, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid)));
|
PrintAndLogEx(SUCCESS, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid)));
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm)));
|
PrintAndLogEx(SUCCESS, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm)));
|
||||||
PrintAndLogEx(NORMAL, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode)));
|
PrintAndLogEx(SUCCESS, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode)));
|
||||||
PrintAndLogEx(NORMAL, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt)));
|
PrintAndLogEx(SUCCESS, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt)));
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode)));
|
PrintAndLogEx(SUCCESS, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode)));
|
||||||
set_last_known_card(card);
|
set_last_known_card(card);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,15 +334,15 @@ static void fuse_config(const picopass_hdr *hdr) {
|
||||||
if (isset(fuses, FUSE_FPERS))
|
if (isset(fuses, FUSE_FPERS))
|
||||||
PrintAndLogEx(SUCCESS, " Mode: Personalization [Programmable]");
|
PrintAndLogEx(SUCCESS, " Mode: Personalization [Programmable]");
|
||||||
else
|
else
|
||||||
PrintAndLogEx(NORMAL, " Mode: Application [Locked]");
|
PrintAndLogEx(SUCCESS, " Mode: Application [Locked]");
|
||||||
|
|
||||||
if (isset(fuses, FUSE_CODING1)) {
|
if (isset(fuses, FUSE_CODING1)) {
|
||||||
PrintAndLogEx(NORMAL, " Coding: RFU");
|
PrintAndLogEx(SUCCESS, " Coding: RFU");
|
||||||
} else {
|
} else {
|
||||||
if (isset(fuses, FUSE_CODING0))
|
if (isset(fuses, FUSE_CODING0))
|
||||||
PrintAndLogEx(NORMAL, " Coding: ISO 14443-2 B/ISO 15693");
|
PrintAndLogEx(SUCCESS, " Coding: ISO 14443-2 B/ISO 15693");
|
||||||
else
|
else
|
||||||
PrintAndLogEx(NORMAL, " Coding: ISO 14443B only");
|
PrintAndLogEx(SUCCESS, " Coding: ISO 14443B only");
|
||||||
}
|
}
|
||||||
// 1 1
|
// 1 1
|
||||||
if (isset(fuses, FUSE_CRYPT1) && isset(fuses, FUSE_CRYPT0)) PrintAndLogEx(SUCCESS, " Crypt: Secured page, keys not locked");
|
if (isset(fuses, FUSE_CRYPT1) && isset(fuses, FUSE_CRYPT0)) PrintAndLogEx(SUCCESS, " Crypt: Secured page, keys not locked");
|
||||||
|
@ -354,7 +354,7 @@ static void fuse_config(const picopass_hdr *hdr) {
|
||||||
if (notset(fuses, FUSE_CRYPT1) && notset(fuses, FUSE_CRYPT0)) PrintAndLogEx(NORMAL, " Crypt: No auth possible. Read only if RA is enabled");
|
if (notset(fuses, FUSE_CRYPT1) && notset(fuses, FUSE_CRYPT0)) PrintAndLogEx(NORMAL, " Crypt: No auth possible. Read only if RA is enabled");
|
||||||
|
|
||||||
if (isset(fuses, FUSE_RA))
|
if (isset(fuses, FUSE_RA))
|
||||||
PrintAndLogEx(NORMAL, " RA: Read access enabled");
|
PrintAndLogEx(SUCCESS, " RA: Read access enabled");
|
||||||
else
|
else
|
||||||
PrintAndLogEx(WARNING, " RA: Read access not enabled");
|
PrintAndLogEx(WARNING, " RA: Read access not enabled");
|
||||||
}
|
}
|
||||||
|
@ -2827,12 +2827,13 @@ int readIclass(bool loop, bool verbose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readStatus & FLAG_ICLASS_READER_CSN) {
|
if (readStatus & FLAG_ICLASS_READER_CSN) {
|
||||||
PrintAndLogEx(NORMAL, " CSN: %s", sprint_hex(data, 8));
|
PrintAndLogEx(NORMAL, "\n");
|
||||||
|
PrintAndLogEx(SUCCESS, " CSN: %s", sprint_hex(data, 8));
|
||||||
tagFound = true;
|
tagFound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readStatus & FLAG_ICLASS_READER_CC) {
|
if (readStatus & FLAG_ICLASS_READER_CC) {
|
||||||
PrintAndLogEx(NORMAL, " CC: %s", sprint_hex(data + 16, 8));
|
PrintAndLogEx(SUCCESS, " CC: %s", sprint_hex(data + 16, 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readStatus & FLAG_ICLASS_READER_CONF) {
|
if (readStatus & FLAG_ICLASS_READER_CONF) {
|
||||||
|
@ -2847,7 +2848,7 @@ int readIclass(bool loop, bool verbose) {
|
||||||
|
|
||||||
bool se_enabled = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
|
bool se_enabled = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " App IA: %s", sprint_hex(data + 8 * 5, 8));
|
PrintAndLogEx(SUCCESS, " App IA: %s", sprint_hex(data + 8 * 5, 8));
|
||||||
|
|
||||||
if (isHidRange) {
|
if (isHidRange) {
|
||||||
if (legacy)
|
if (legacy)
|
||||||
|
|
|
@ -210,7 +210,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
crc = data[4];
|
crc = data[4];
|
||||||
uint32_t calc_crc = CRC8Legic(data, 4);
|
uint32_t calc_crc = CRC8Legic(data, 4);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("CDF: System Area"));
|
PrintAndLogEx(SUCCESS, _YELLOW_("CDF: System Area"));
|
||||||
PrintAndLogEx(NORMAL, "------------------------------------------------------");
|
PrintAndLogEx(NORMAL, "------------------------------------------------------");
|
||||||
PrintAndLogEx(NORMAL, "MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s",
|
PrintAndLogEx(NORMAL, "MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s",
|
||||||
data[0],
|
data[0],
|
||||||
|
@ -229,7 +229,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
// New unwritten media?
|
// New unwritten media?
|
||||||
if (dcf == 0xFFFF) {
|
if (dcf == 0xFFFF) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type=NM (New Media)",
|
PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type=NM (New Media)",
|
||||||
dcf,
|
dcf,
|
||||||
data[5],
|
data[5],
|
||||||
data[6]
|
data[6]
|
||||||
|
@ -262,7 +262,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
stamp_len = 0xfc - data[6];
|
stamp_len = 0xfc - data[6];
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type=" _YELLOW_("%s") " (OLE=%01u), OL=%02u, FL=%02u",
|
PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type=" _YELLOW_("%s") " (OLE=%01u), OL=%02u, FL=%02u",
|
||||||
dcf,
|
dcf,
|
||||||
data[5],
|
data[5],
|
||||||
data[6],
|
data[6],
|
||||||
|
@ -281,7 +281,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
strncpy(token_type, "IM", sizeof(token_type) - 1);
|
strncpy(token_type, "IM", sizeof(token_type) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type = %s (OLE = %01u)",
|
PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type = %s (OLE = %01u)",
|
||||||
dcf,
|
dcf,
|
||||||
data[5],
|
data[5],
|
||||||
data[6],
|
data[6],
|
||||||
|
@ -294,7 +294,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
if (dcf != 0xFFFF) {
|
if (dcf != 0xFFFF) {
|
||||||
|
|
||||||
if (bIsSegmented) {
|
if (bIsSegmented) {
|
||||||
PrintAndLogEx(NORMAL, "WRP = %02u, WRC = %01u, RD = %01u, SSC = %02X",
|
PrintAndLogEx(SUCCESS, "WRP = %02u, WRC = %01u, RD = %01u, SSC = %02X",
|
||||||
data[7] & 0x0f,
|
data[7] & 0x0f,
|
||||||
(data[7] & 0x70) >> 4,
|
(data[7] & 0x70) >> 4,
|
||||||
(data[7] & 0x80) >> 7,
|
(data[7] & 0x80) >> 7,
|
||||||
|
@ -305,11 +305,11 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
// Header area is only available on IM-S cards, on master tokens this data is the master token data itself
|
// Header area is only available on IM-S cards, on master tokens this data is the master token data itself
|
||||||
if (bIsSegmented || dcf > 60000) {
|
if (bIsSegmented || dcf > 60000) {
|
||||||
if (dcf > 60000) {
|
if (dcf > 60000) {
|
||||||
PrintAndLogEx(NORMAL, "Master token data");
|
PrintAndLogEx(SUCCESS, "Master token data");
|
||||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 8, 14));
|
PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 8, 14));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, "Remaining Header Area");
|
PrintAndLogEx(SUCCESS, "Remaining Header Area");
|
||||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 9, 13));
|
PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 9, 13));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
if (dcf > 60000)
|
if (dcf > 60000)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\nADF: User Area"));
|
PrintAndLogEx(SUCCESS, _YELLOW_("\nADF: User Area"));
|
||||||
PrintAndLogEx(NORMAL, "------------------------------------------------------");
|
PrintAndLogEx(NORMAL, "------------------------------------------------------");
|
||||||
|
|
||||||
if (bIsSegmented) {
|
if (bIsSegmented) {
|
||||||
|
@ -356,20 +356,20 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
segCalcCRC = CRC8Legic(segCrcBytes, 8);
|
segCalcCRC = CRC8Legic(segCrcBytes, 8);
|
||||||
segCRC = data[i + 4] ^ crc;
|
segCRC = data[i + 4] ^ crc;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Segment | %02u ", segmentNum);
|
PrintAndLogEx(SUCCESS, "Segment | %02u ", segmentNum);
|
||||||
PrintAndLogEx(NORMAL, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X",
|
PrintAndLogEx(SUCCESS, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X",
|
||||||
data[i] ^ crc,
|
data[i] ^ crc,
|
||||||
data[i + 1] ^ crc,
|
data[i + 1] ^ crc,
|
||||||
data[i + 2] ^ crc,
|
data[i + 2] ^ crc,
|
||||||
data[i + 3] ^ crc
|
data[i + 3] ^ crc
|
||||||
);
|
);
|
||||||
PrintAndLogEx(NORMAL, "Segment len | %u, Flag: 0x%X (valid:%01u, last:%01u)",
|
PrintAndLogEx(SUCCESS, "Segment len | %u, Flag: 0x%X (valid:%01u, last:%01u)",
|
||||||
segment_len,
|
segment_len,
|
||||||
segment_flag,
|
segment_flag,
|
||||||
(segment_flag & 0x4) >> 2,
|
(segment_flag & 0x4) >> 2,
|
||||||
(segment_flag & 0x8) >> 3
|
(segment_flag & 0x8) >> 3
|
||||||
);
|
);
|
||||||
PrintAndLogEx(NORMAL, " | WRP: %02u, WRC: %02u, RD: %01u, CRC: 0x%02X (%s)",
|
PrintAndLogEx(SUCCESS, " | WRP: %02u, WRC: %02u, RD: %01u, CRC: 0x%02X (%s)",
|
||||||
wrp,
|
wrp,
|
||||||
wrc,
|
wrc,
|
||||||
((data[i + 3] ^ crc) & 0x80) >> 7,
|
((data[i + 3] ^ crc) & 0x80) >> 7,
|
||||||
|
@ -380,7 +380,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
i += 5;
|
i += 5;
|
||||||
|
|
||||||
if (hasWRC) {
|
if (hasWRC) {
|
||||||
PrintAndLogEx(NORMAL, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
|
PrintAndLogEx(SUCCESS, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasWRP) {
|
if (hasWRP) {
|
||||||
PrintAndLogEx(NORMAL, "Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)", i, k, wrc, wrp, wrp_len);
|
PrintAndLogEx(SUCCESS, "Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)", i, k, wrc, wrp, wrp_len);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
|
|
||||||
// does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
|
// does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
|
||||||
if (wrp_len == 8) {
|
if (wrp_len == 8) {
|
||||||
PrintAndLogEx(NORMAL, "Card ID: " _YELLOW_("%2X%02X%02X"),
|
PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"),
|
||||||
data[i - 4] ^ crc,
|
data[i - 4] ^ crc,
|
||||||
data[i - 3] ^ crc,
|
data[i - 3] ^ crc,
|
||||||
data[i - 2] ^ crc
|
data[i - 2] ^ crc
|
||||||
|
@ -414,7 +414,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (remain_seg_payload_len > 0) {
|
if (remain_seg_payload_len > 0) {
|
||||||
PrintAndLogEx(NORMAL, "Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
|
PrintAndLogEx(SUCCESS, "Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
||||||
|
|
||||||
|
@ -444,14 +444,14 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
int wrp_len = (wrp - wrc);
|
int wrp_len = (wrp - wrc);
|
||||||
int remain_seg_payload_len = (card.cardsize - 22 - wrp);
|
int remain_seg_payload_len = (card.cardsize - 22 - wrp);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
|
PrintAndLogEx(SUCCESS, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
|
||||||
wrp,
|
wrp,
|
||||||
wrc,
|
wrc,
|
||||||
(data[7] & 0x80) >> 7
|
(data[7] & 0x80) >> 7
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hasWRC) {
|
if (hasWRC) {
|
||||||
PrintAndLogEx(NORMAL, "WRC protected area: (I %d | WRC %d)", i, wrc);
|
PrintAndLogEx(SUCCESS, "WRC protected area: (I %d | WRC %d)", i, wrc);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
||||||
print_hex_break(data + i, wrc, 16);
|
print_hex_break(data + i, wrc, 16);
|
||||||
|
@ -460,7 +460,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasWRP) {
|
if (hasWRP) {
|
||||||
PrintAndLogEx(NORMAL, "Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len);
|
PrintAndLogEx(SUCCESS, "Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
||||||
print_hex_break(data + i, wrp_len, 16);
|
print_hex_break(data + i, wrp_len, 16);
|
||||||
|
@ -470,7 +470,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
// Q: does this one work?
|
// Q: does this one work?
|
||||||
// A: Only if KGH/BGH is used with BCD encoded card number. Maybe this will show just garbage
|
// A: Only if KGH/BGH is used with BCD encoded card number. Maybe this will show just garbage
|
||||||
if (wrp_len == 8) {
|
if (wrp_len == 8) {
|
||||||
PrintAndLogEx(NORMAL, "Card ID: " _YELLOW_("%2X%02X%02X"),
|
PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"),
|
||||||
data[i - 4],
|
data[i - 4],
|
||||||
data[i - 3],
|
data[i - 3],
|
||||||
data[i - 2]
|
data[i - 2]
|
||||||
|
@ -479,7 +479,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remain_seg_payload_len > 0) {
|
if (remain_seg_payload_len > 0) {
|
||||||
PrintAndLogEx(NORMAL, "Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
|
PrintAndLogEx(SUCCESS, "Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
|
||||||
print_hex_break(data + i, remain_seg_payload_len, 16);
|
print_hex_break(data + i, remain_seg_payload_len, 16);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "cmdparser.h" // command_t
|
#include "cmdparser.h" // command_t
|
||||||
#include "commonutil.h" // ARRAYLEN
|
#include "commonutil.h" // ARRAYLEN
|
||||||
#include "comms.h" // clearCommandBuffer
|
#include "comms.h" // clearCommandBuffer
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
#include "cmdtrace.h"
|
#include "cmdtrace.h"
|
||||||
|
@ -3665,6 +3665,56 @@ static int CmdHF14AMfCSetUID(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmdHF14AMfCWipe(const char *cmd) {
|
||||||
|
uint8_t uid[8] = {0x00};
|
||||||
|
int uidLen = 0;
|
||||||
|
uint8_t atqa[2] = {0x00};
|
||||||
|
int atqaLen = 0;
|
||||||
|
uint8_t sak[1] = {0x00};
|
||||||
|
int sakLen = 0;
|
||||||
|
|
||||||
|
CLIParserInit("hf mf cwipe",
|
||||||
|
"Wipe gen1 magic chinese card. Set UID/ATQA/SAK/Data/Keys/Access to default values.",
|
||||||
|
"Usage:\n\thf mf cwipe -> wipe card.\n"
|
||||||
|
"\thf mfp mf cwipe -u 09080706 -a 0004 -s 18 -> set UID, ATQA and SAK and wipe card.");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("uU", "uid", "<HEX UID (4b)>", "UID for card"),
|
||||||
|
arg_str0("aA", "atqa", "<HEX ATQA (2b)>", "ATQA for card"),
|
||||||
|
arg_str0("sS", "sak", "<HEX SAK (1b)>", "SAK for card"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(cmd, argtable, true);
|
||||||
|
|
||||||
|
CLIGetHexWithReturn(1, uid, &uidLen);
|
||||||
|
CLIGetHexWithReturn(2, atqa, &atqaLen);
|
||||||
|
CLIGetHexWithReturn(3, sak, &sakLen);
|
||||||
|
CLIParserFree();
|
||||||
|
|
||||||
|
if (uidLen && uidLen != 4) {
|
||||||
|
PrintAndLogEx(ERR, "UID length must be 4 bytes instead of: %d", uidLen);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (atqaLen && atqaLen != 2) {
|
||||||
|
PrintAndLogEx(ERR, "UID length must be 2 bytes instead of: %d", atqaLen);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (sakLen && sakLen != 1) {
|
||||||
|
PrintAndLogEx(ERR, "UID length must be 1 byte instead of: %d", sakLen);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = mfCWipe((uidLen) ? uid : NULL, (atqaLen) ? atqa : NULL, (sakLen) ? sak : NULL);
|
||||||
|
if (res) {
|
||||||
|
PrintAndLogEx(ERR, "Can't wipe card. error=%d", res);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Card wiped successfully");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdHF14AMfCSetBlk(const char *Cmd) {
|
static int CmdHF14AMfCSetBlk(const char *Cmd) {
|
||||||
uint8_t block[16] = {0x00};
|
uint8_t block[16] = {0x00};
|
||||||
uint8_t blockNo = 0;
|
uint8_t blockNo = 0;
|
||||||
|
@ -4211,7 +4261,7 @@ static int CmdHF14AMfAuth4(const char *Cmd) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MifareAuth4(NULL, keyn, key, true, false, true);
|
return MifareAuth4(NULL, keyn, key, true, false, true, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.nxp.com/docs/en/application-note/AN10787.pdf
|
// https://www.nxp.com/docs/en/application-note/AN10787.pdf
|
||||||
|
@ -4446,6 +4496,7 @@ static command_t CommandTable[] = {
|
||||||
{"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from simulator memory"},
|
{"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from simulator memory"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||||
{"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID (magic chinese card)"},
|
{"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID (magic chinese card)"},
|
||||||
|
{"cwipe", CmdHF14AMfCWipe, IfPm3Iso14443a, "Wipe card to default UID/Sectors/Keys"},
|
||||||
{"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block (magic chinese card)"},
|
{"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block (magic chinese card)"},
|
||||||
{"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block (magic chinese card)"},
|
{"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block (magic chinese card)"},
|
||||||
{"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector (magic chinese card)"},
|
{"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector (magic chinese card)"},
|
||||||
|
|
|
@ -33,7 +33,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return 0;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||||
if (!isOK) {
|
if (!isOK) {
|
||||||
|
@ -49,7 +49,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
PrintAndLogEx(WARNING, "Command unsuccessful");
|
PrintAndLogEx(WARNING, "Command unsuccessful");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "-- Desfire Information --------------------------------------");
|
PrintAndLogEx(NORMAL, "-- Desfire Information --------------------------------------");
|
||||||
|
@ -82,7 +82,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
uint8_t data[1] = {GET_FREE_MEMORY};
|
uint8_t data[1] = {GET_FREE_MEMORY};
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), 0x01, 0, data, sizeof(data));
|
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), 0x01, 0, data, sizeof(data));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500))
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500))
|
||||||
return 0;
|
return PM3_ETIMEOUT;
|
||||||
|
|
||||||
uint8_t tmp[3];
|
uint8_t tmp[3];
|
||||||
memcpy(tmp, resp.data.asBytes + 3, 3);
|
memcpy(tmp, resp.data.asBytes + 3, 3);
|
||||||
|
@ -105,7 +105,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return 1;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -189,10 +189,12 @@ void getKeySettings(uint8_t *aid) {
|
||||||
PrintAndLogEx(NORMAL, " [0x02] Directory list access with CMK : %s", str);
|
PrintAndLogEx(NORMAL, " [0x02] Directory list access with CMK : %s", str);
|
||||||
str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO";
|
str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO";
|
||||||
PrintAndLogEx(NORMAL, " [0x01] CMK is changeable : %s", str);
|
PrintAndLogEx(NORMAL, " [0x01] CMK is changeable : %s", str);
|
||||||
|
|
||||||
{
|
{
|
||||||
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64
|
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { return; }
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { return; }
|
||||||
isOK = resp.oldarg[0] & 0xff;
|
isOK = resp.oldarg[0] & 0xff;
|
||||||
if (!isOK) {
|
if (!isOK) {
|
||||||
|
@ -206,24 +208,27 @@ void getKeySettings(uint8_t *aid) {
|
||||||
|
|
||||||
{
|
{
|
||||||
uint8_t data[2] = {AUTHENTICATE, 0}; // 0x0A, KEY 0
|
uint8_t data[2] = {AUTHENTICATE, 0}; // 0x0A, KEY 0
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
|
||||||
isOK = resp.data.asBytes[2] & 0xff;
|
isOK = resp.data.asBytes[2] & 0xff;
|
||||||
PrintAndLogEx(NORMAL, " [0x0A] Authenticate : %s", (isOK == 0xAE) ? "NO" : "YES");
|
PrintAndLogEx(NORMAL, " [0x0A] Authenticate : %s", (isOK == 0xAE) ? "NO" : "YES");
|
||||||
|
|
||||||
{
|
{
|
||||||
uint8_t data[2] = {AUTHENTICATE_ISO, 0}; // 0x1A, KEY 0
|
uint8_t data[2] = {AUTHENTICATE_ISO, 0}; // 0x1A, KEY 0
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
|
||||||
isOK = resp.data.asBytes[2] & 0xff;
|
isOK = resp.data.asBytes[2] & 0xff;
|
||||||
PrintAndLogEx(NORMAL, " [0x1A] Authenticate ISO : %s", (isOK == 0xAE) ? "NO" : "YES");
|
PrintAndLogEx(NORMAL, " [0x1A] Authenticate ISO : %s", (isOK == 0xAE) ? "NO" : "YES");
|
||||||
|
|
||||||
{
|
{
|
||||||
uint8_t data[2] = {AUTHENTICATE_AES, 0}; // 0xAA, KEY 0
|
uint8_t data[2] = {AUTHENTICATE_AES, 0}; // 0xAA, KEY 0
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
|
||||||
isOK = resp.data.asBytes[2] & 0xff;
|
isOK = resp.data.asBytes[2] & 0xff;
|
||||||
PrintAndLogEx(NORMAL, " [0xAA] Authenticate AES : %s", (isOK == 0xAE) ? "NO" : "YES");
|
PrintAndLogEx(NORMAL, " [0xAA] Authenticate AES : %s", (isOK == 0xAE) ? "NO" : "YES");
|
||||||
|
@ -237,7 +242,7 @@ void getKeySettings(uint8_t *aid) {
|
||||||
{
|
{
|
||||||
uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a
|
uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a
|
||||||
memcpy(data + 1, aid, 3);
|
memcpy(data + 1, aid, 3);
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(WARNING, " Timed-out");
|
PrintAndLogEx(WARNING, " Timed-out");
|
||||||
|
@ -252,8 +257,9 @@ void getKeySettings(uint8_t *aid) {
|
||||||
// KEY SETTINGS
|
// KEY SETTINGS
|
||||||
{
|
{
|
||||||
uint8_t data[1] = {GET_KEY_SETTINGS}; // 0x45
|
uint8_t data[1] = {GET_KEY_SETTINGS}; // 0x45
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -294,8 +300,9 @@ void getKeySettings(uint8_t *aid) {
|
||||||
// KEY VERSION - AMK
|
// KEY VERSION - AMK
|
||||||
{
|
{
|
||||||
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64
|
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(WARNING, " Timed-out");
|
PrintAndLogEx(WARNING, " Timed-out");
|
||||||
return;
|
return;
|
||||||
|
@ -318,11 +325,10 @@ void getKeySettings(uint8_t *aid) {
|
||||||
// LOOP over numOfKeys that we got before.
|
// LOOP over numOfKeys that we got before.
|
||||||
// From 0x01 to numOfKeys. We already got 0x00. (AMK)
|
// From 0x01 to numOfKeys. We already got 0x00. (AMK)
|
||||||
// TODO (iceman)
|
// TODO (iceman)
|
||||||
for (int i = 0x01; i <= 0x0f; ++i) {
|
/*
|
||||||
|
for (int i = 0x01; i <= 0x0f; ++i) {
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,17 +339,18 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
|
||||||
uint8_t aid[3];
|
uint8_t aid[3];
|
||||||
{
|
{
|
||||||
uint8_t data[1] = {GET_APPLICATION_IDS}; //0x6a
|
uint8_t data[1] = {GET_APPLICATION_IDS}; //0x6a
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
return 0;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
isOK = resp.oldarg[0] & 0xff;
|
isOK = resp.oldarg[0] & 0xff;
|
||||||
if (!isOK) {
|
if (!isOK) {
|
||||||
PrintAndLogEx(NORMAL, "Command unsuccessful");
|
PrintAndLogEx(NORMAL, "Command unsuccessful");
|
||||||
return 0;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "-- Desfire Enumerate Applications ---------------------------");
|
PrintAndLogEx(NORMAL, "-- Desfire Enumerate Applications ---------------------------");
|
||||||
|
@ -368,7 +375,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
|
||||||
{
|
{
|
||||||
uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a
|
uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a
|
||||||
memcpy(data + 1, &resp.data.asBytes[i], 3);
|
memcpy(data + 1, &resp.data.asBytes[i], 3);
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &respAid, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &respAid, 1500)) {
|
||||||
|
@ -384,7 +391,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
|
||||||
// Get File IDs
|
// Get File IDs
|
||||||
{
|
{
|
||||||
uint8_t data[1] = {GET_FILE_IDS}; // 0x6f
|
uint8_t data[1] = {GET_FILE_IDS}; // 0x6f
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
|
||||||
|
@ -405,7 +412,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
|
||||||
// Get ISO File IDs
|
// Get ISO File IDs
|
||||||
{
|
{
|
||||||
uint8_t data[1] = {GET_ISOFILE_IDS}; // 0x61
|
uint8_t data[1] = {GET_ISOFILE_IDS}; // 0x61
|
||||||
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
|
||||||
|
@ -422,13 +429,9 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MIAFRE DesFire Authentication
|
// MIAFRE DesFire Authentication
|
||||||
|
@ -456,7 +459,7 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " hf mfdes auth 1 1 0 11223344");
|
PrintAndLogEx(NORMAL, " hf mfdes auth 1 1 0 11223344");
|
||||||
PrintAndLogEx(NORMAL, " hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f");
|
PrintAndLogEx(NORMAL, " hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
uint8_t cmdAuthMode = param_get8(Cmd, 0);
|
uint8_t cmdAuthMode = param_get8(Cmd, 0);
|
||||||
uint8_t cmdAuthAlgo = param_get8(Cmd, 1);
|
uint8_t cmdAuthAlgo = param_get8(Cmd, 1);
|
||||||
|
@ -466,25 +469,24 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
||||||
case 1:
|
case 1:
|
||||||
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) {
|
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) {
|
||||||
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
|
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) {
|
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) {
|
||||||
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
|
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (cmdAuthAlgo != 4) {
|
if (cmdAuthAlgo != 4) {
|
||||||
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
|
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(WARNING, "Wrong Auth mode");
|
PrintAndLogEx(WARNING, "Wrong Auth mode");
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cmdAuthAlgo) {
|
switch (cmdAuthAlgo) {
|
||||||
|
@ -510,8 +512,9 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
||||||
// key
|
// key
|
||||||
if (param_gethex(Cmd, 3, key, keylength * 2)) {
|
if (param_gethex(Cmd, 3, key, keylength * 2)) {
|
||||||
PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength);
|
PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength);
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
// algo, keylength,
|
// algo, keylength,
|
||||||
uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES)
|
uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES)
|
||||||
memcpy(data + 1, key, keylength);
|
memcpy(data + 1, key, keylength);
|
||||||
|
@ -521,7 +524,7 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
|
||||||
PrintAndLogEx(WARNING, "Client command execute timeout");
|
PrintAndLogEx(WARNING, "Client command execute timeout");
|
||||||
return 0;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||||
|
@ -536,7 +539,7 @@ static int CmdHF14ADesAuth(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "Client command failed.");
|
PrintAndLogEx(NORMAL, "Client command failed.");
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
||||||
return 1;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -553,7 +556,7 @@ static command_t CommandTable[] = {
|
||||||
static int CmdHelp(const char *Cmd) {
|
static int CmdHelp(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
CmdsHelp(CommandTable);
|
CmdsHelp(CommandTable);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdHFMFDes(const char *Cmd) {
|
int CmdHFMFDes(const char *Cmd) {
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include "cliparser/cliparser.h"
|
#include "cliparser/cliparser.h"
|
||||||
#include "emv/dump.h"
|
#include "emv/dump.h"
|
||||||
#include "mifare/mifaredefault.h"
|
#include "mifare/mifaredefault.h"
|
||||||
|
#include "util_posix.h"
|
||||||
|
#include "fileutils.h"
|
||||||
|
|
||||||
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ static int CmdHFMFPInfo(const char *cmd) {
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
// https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161
|
// https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161
|
||||||
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
|
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
|
||||||
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen);
|
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false);
|
||||||
if (!res && datalen > 1 && data[0] == 0x09) {
|
if (!res && datalen > 1 && data[0] == 0x09) {
|
||||||
SLmode = 0;
|
SLmode = 0;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +107,7 @@ static int CmdHFMFPInfo(const char *cmd) {
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFMFPWritePerso(const char *cmd) {
|
static int CmdHFMFPWritePerso(const char *cmd) {
|
||||||
|
@ -169,7 +171,7 @@ static int CmdHFMFPWritePerso(const char *cmd) {
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "Write OK.");
|
PrintAndLogEx(INFO, "Write OK.");
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
|
uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
|
||||||
|
@ -245,7 +247,7 @@ static int CmdHFMFPInitPerso(const char *cmd) {
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Done.");
|
PrintAndLogEx(INFO, "Done.");
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFMFPCommitPerso(const char *cmd) {
|
static int CmdHFMFPCommitPerso(const char *cmd) {
|
||||||
|
@ -286,7 +288,7 @@ static int CmdHFMFPCommitPerso(const char *cmd) {
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "Switch level OK.");
|
PrintAndLogEx(INFO, "Switch level OK.");
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFMFPAuth(const char *cmd) {
|
static int CmdHFMFPAuth(const char *cmd) {
|
||||||
|
@ -324,7 +326,7 @@ static int CmdHFMFPAuth(const char *cmd) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MifareAuth4(NULL, keyn, key, true, false, verbose);
|
return MifareAuth4(NULL, keyn, key, true, false, true, verbose, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFMFPRdbl(const char *cmd) {
|
static int CmdHFMFPRdbl(const char *cmd) {
|
||||||
|
@ -392,7 +394,7 @@ static int CmdHFMFPRdbl(const char *cmd) {
|
||||||
PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
|
PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
|
||||||
|
|
||||||
mf4Session mf4session;
|
mf4Session mf4session;
|
||||||
int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose);
|
int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Authentication error: %d", res);
|
PrintAndLogEx(ERR, "Authentication error: %d", res);
|
||||||
return res;
|
return res;
|
||||||
|
@ -491,7 +493,7 @@ static int CmdHFMFPRdsc(const char *cmd) {
|
||||||
PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
|
PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
|
||||||
|
|
||||||
mf4Session mf4session;
|
mf4Session mf4session;
|
||||||
int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose);
|
int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Authentication error: %d", res);
|
PrintAndLogEx(ERR, "Authentication error: %d", res);
|
||||||
return res;
|
return res;
|
||||||
|
@ -532,7 +534,7 @@ static int CmdHFMFPRdsc(const char *cmd) {
|
||||||
}
|
}
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFMFPWrbl(const char *cmd) {
|
static int CmdHFMFPWrbl(const char *cmd) {
|
||||||
|
@ -595,7 +597,7 @@ static int CmdHFMFPWrbl(const char *cmd) {
|
||||||
PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
|
PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
|
||||||
|
|
||||||
mf4Session mf4session;
|
mf4Session mf4session;
|
||||||
int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose);
|
int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Authentication error: %d", res);
|
PrintAndLogEx(ERR, "Authentication error: %d", res);
|
||||||
return res;
|
return res;
|
||||||
|
@ -634,7 +636,333 @@ static int CmdHFMFPWrbl(const char *cmd) {
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
PrintAndLogEx(INFO, "Write OK.");
|
PrintAndLogEx(INFO, "Write OK.");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AES_KEY_LEN 16
|
||||||
|
#define MAX_KEYS_LIST_LEN 1024
|
||||||
|
|
||||||
|
int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
|
||||||
|
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
|
||||||
|
bool verbose) {
|
||||||
|
int res;
|
||||||
|
bool selectCard = true;
|
||||||
|
uint8_t keyn[2] = {0};
|
||||||
|
|
||||||
|
// sector number from 0
|
||||||
|
for (uint8_t sector = startSector; sector <= endSector; sector++) {
|
||||||
|
// 0-keyA 1-keyB
|
||||||
|
for (uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) {
|
||||||
|
// main cycle with key check
|
||||||
|
for (int i = 0; i < keyListLen; i++) {
|
||||||
|
if (i % 10 == 0) {
|
||||||
|
if (!verbose)
|
||||||
|
printf(".");
|
||||||
|
if (kbd_enter_pressed()) {
|
||||||
|
PrintAndLogEx(WARNING, "\nAborted via keyboard!\n");
|
||||||
|
DropField();
|
||||||
|
return PM3_EOPABORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB;
|
||||||
|
keyn[0] = uKeyNum >> 8;
|
||||||
|
keyn[1] = uKeyNum & 0xff;
|
||||||
|
|
||||||
|
for (int retry = 0; retry < 4; retry++) {
|
||||||
|
res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true);
|
||||||
|
if (res != 2)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(WARNING, "retried[%d]...", retry);
|
||||||
|
else
|
||||||
|
printf("R");
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
selectCard = true;
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(WARNING, "sector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res);
|
||||||
|
|
||||||
|
// key for [sector,keyAB] found
|
||||||
|
if (res == 0) {
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16));
|
||||||
|
else
|
||||||
|
printf("+");
|
||||||
|
foundKeys[keyAB][sector][0] = 0x01;
|
||||||
|
memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN);
|
||||||
|
DropField();
|
||||||
|
selectCard = true;
|
||||||
|
msleep(50);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5 - auth error (rnd not equal)
|
||||||
|
if (res != 5) {
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(ERR, "Exchange error. Aborted.");
|
||||||
|
else
|
||||||
|
printf("E");
|
||||||
|
DropField();
|
||||||
|
return PM3_ECARDEXCHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectCard = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyListLen, uint32_t *startPattern) {
|
||||||
|
for (uint32_t pt = *startPattern; pt < 0x10000; pt++) {
|
||||||
|
keyList[*keyListLen][0] = (pt >> 8) & 0xff;
|
||||||
|
keyList[*keyListLen][1] = pt & 0xff;
|
||||||
|
memcpy(&keyList[*keyListLen][2], &keyList[*keyListLen][0], 2);
|
||||||
|
memcpy(&keyList[*keyListLen][4], &keyList[*keyListLen][0], 4);
|
||||||
|
memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8);
|
||||||
|
(*keyListLen)++;
|
||||||
|
*startPattern = pt;
|
||||||
|
if (*keyListLen == MAX_KEYS_LIST_LEN)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(*startPattern)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFMFPChk(const char *cmd) {
|
||||||
|
int res;
|
||||||
|
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
|
||||||
|
size_t keyListLen = 0;
|
||||||
|
uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}};
|
||||||
|
|
||||||
|
CLIParserInit("hf mfp chk",
|
||||||
|
"Checks keys with Mifare Plus card.",
|
||||||
|
"Usage:\n"
|
||||||
|
" hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
|
||||||
|
" hf mfp chk -s 2 -a -> check default key list on sector 2, key A\n"
|
||||||
|
" hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
|
||||||
|
" hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n"
|
||||||
|
" hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0("aA", "keya", "check only key A (by default check all keys)."),
|
||||||
|
arg_lit0("bB", "keyb", "check only key B (by default check all keys)."),
|
||||||
|
arg_int0("sS", "startsec", "Start sector Num (0..255)", NULL),
|
||||||
|
arg_int0("eE", "endsec", "End sector Num (0..255)", NULL),
|
||||||
|
arg_str0("kK", "key", "<Key>", "Key for checking (HEX 16 bytes)"),
|
||||||
|
arg_str0("dD", "dict", "<file>", "file with keys dictionary"),
|
||||||
|
arg_lit0(NULL, "pattern1b", "check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
|
||||||
|
arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
|
||||||
|
arg_str0(NULL, "startp2b", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
||||||
|
arg_str0("jJ", "json", "<file>", "json file to save keys"),
|
||||||
|
arg_lit0("vV", "verbose", "verbose mode."),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(cmd, argtable, true);
|
||||||
|
|
||||||
|
bool keyA = arg_get_lit(1);
|
||||||
|
bool keyB = arg_get_lit(2);
|
||||||
|
uint8_t startSector = arg_get_int_def(3, 0);
|
||||||
|
uint8_t endSector = arg_get_int_def(4, 0);
|
||||||
|
|
||||||
|
uint8_t vkey[16] = {0};
|
||||||
|
int vkeylen = 0;
|
||||||
|
CLIGetHexWithReturn(5, vkey, &vkeylen);
|
||||||
|
if (vkeylen > 0) {
|
||||||
|
if (vkeylen == 16) {
|
||||||
|
memcpy(&keyList[keyListLen], vkey, 16);
|
||||||
|
keyListLen++;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(ERR, "Specified key must have 16 bytes length.");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0};
|
||||||
|
int dict_filenamelen = 0;
|
||||||
|
if (CLIParamStrToBuf(arg_get_str(6), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) {
|
||||||
|
PrintAndLogEx(FAILED, "File name too long or invalid.");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pattern1b = arg_get_lit(7);
|
||||||
|
bool pattern2b = arg_get_lit(8);
|
||||||
|
|
||||||
|
if (pattern1b && pattern2b) {
|
||||||
|
PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only.");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dict_filenamelen && (pattern1b || pattern2b)) {
|
||||||
|
PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command.");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t startPattern = 0x0000;
|
||||||
|
uint8_t vpattern[2];
|
||||||
|
int vpatternlen = 0;
|
||||||
|
CLIGetHexWithReturn(9, vpattern, &vpatternlen);
|
||||||
|
if (vpatternlen > 0) {
|
||||||
|
if (vpatternlen > 0 && vpatternlen <= 2) {
|
||||||
|
startPattern = (vpattern[0] << 8) + vpattern[1];
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(ERR, "Pattern must be 2-byte length.");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (!pattern2b)
|
||||||
|
PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search.");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t jsonname[250] = {0};
|
||||||
|
int jsonnamelen = 0;
|
||||||
|
if (CLIParamStrToBuf(arg_get_str(10), jsonname, sizeof(jsonname), &jsonnamelen)) {
|
||||||
|
PrintAndLogEx(ERR, "Invalid json name.");
|
||||||
|
CLIParserFree();
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
jsonname[jsonnamelen] = 0;
|
||||||
|
|
||||||
|
bool verbose = arg_get_lit(11);
|
||||||
|
|
||||||
|
CLIParserFree();
|
||||||
|
|
||||||
|
uint8_t startKeyAB = 0;
|
||||||
|
uint8_t endKeyAB = 1;
|
||||||
|
if (keyA && !keyB)
|
||||||
|
endKeyAB = 0;
|
||||||
|
if (!keyA && keyB)
|
||||||
|
startKeyAB = 1;
|
||||||
|
|
||||||
|
if (endSector < startSector)
|
||||||
|
endSector = startSector;
|
||||||
|
|
||||||
|
// 1-byte pattern search mode
|
||||||
|
if (pattern1b) {
|
||||||
|
for (int i = 0; i < 0x100; i++)
|
||||||
|
memset(keyList[i], i, 16);
|
||||||
|
|
||||||
|
keyListLen = 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2-byte pattern search mode
|
||||||
|
if (pattern2b)
|
||||||
|
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
||||||
|
|
||||||
|
// dictionary mode
|
||||||
|
size_t endFilePosition = 0;
|
||||||
|
if (dict_filenamelen) {
|
||||||
|
uint16_t keycnt = 0;
|
||||||
|
res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition, true);
|
||||||
|
keyListLen = keycnt;
|
||||||
|
if (endFilePosition)
|
||||||
|
PrintAndLogEx(SUCCESS, "First part of dictionary successfully loaded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyListLen == 0) {
|
||||||
|
for (int i = 0; i < g_mifare_plus_default_keys_len; i++) {
|
||||||
|
if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16)
|
||||||
|
break;
|
||||||
|
|
||||||
|
keyListLen++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyListLen == 0) {
|
||||||
|
PrintAndLogEx(ERR, "Key list is empty. Nothing to check.");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verbose)
|
||||||
|
printf("Search keys:");
|
||||||
|
while (true) {
|
||||||
|
res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose);
|
||||||
|
if (res == PM3_EOPABORTED)
|
||||||
|
break;
|
||||||
|
if (pattern2b && startPattern < 0x10000) {
|
||||||
|
if (!verbose)
|
||||||
|
printf("p");
|
||||||
|
keyListLen = 0;
|
||||||
|
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dict_filenamelen && endFilePosition) {
|
||||||
|
if (!verbose)
|
||||||
|
printf("d");
|
||||||
|
uint16_t keycnt = 0;
|
||||||
|
res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
|
||||||
|
keyListLen = keycnt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!verbose)
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// print result
|
||||||
|
bool printedHeader = false;
|
||||||
|
for (uint8_t sector = startSector; sector <= endSector; sector++) {
|
||||||
|
if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) {
|
||||||
|
if (!printedHeader) {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------.");
|
||||||
|
PrintAndLogEx(INFO, "|sector| key A | key B |");
|
||||||
|
PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|");
|
||||||
|
printedHeader = true;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(INFO, "| %02d |%32s|%32s|",
|
||||||
|
sector,
|
||||||
|
(foundKeys[0][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[0][sector][1], AES_KEY_LEN),
|
||||||
|
(foundKeys[1][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[1][sector][1], AES_KEY_LEN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!printedHeader)
|
||||||
|
PrintAndLogEx(INFO, "No keys found(");
|
||||||
|
else
|
||||||
|
PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'\n");
|
||||||
|
|
||||||
|
// save keys to json
|
||||||
|
if ((jsonnamelen > 0) && printedHeader) {
|
||||||
|
// Mifare Plus info
|
||||||
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
WaitForResponse(CMD_ACK, &resp);
|
||||||
|
|
||||||
|
iso14a_card_select_t card;
|
||||||
|
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||||
|
|
||||||
|
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||||
|
|
||||||
|
uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0};
|
||||||
|
uint8_t atslen = 0;
|
||||||
|
if (select_status == 1 || select_status == 2) {
|
||||||
|
memcpy(data, card.uid, card.uidlen);
|
||||||
|
data[10] = card.sak;
|
||||||
|
data[11] = card.atqa[1];
|
||||||
|
data[12] = card.atqa[0];
|
||||||
|
atslen = card.ats_len;
|
||||||
|
data[13] = atslen;
|
||||||
|
memcpy(&data[14], card.ats, atslen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
|
||||||
|
memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1));
|
||||||
|
saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFMFPMAD(const char *cmd) {
|
static int CmdHFMFPMAD(const char *cmd) {
|
||||||
|
@ -728,7 +1056,7 @@ static int CmdHFMFPMAD(const char *cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFMFPNDEF(const char *cmd) {
|
static int CmdHFMFPNDEF(const char *cmd) {
|
||||||
|
@ -832,7 +1160,7 @@ static int CmdHFMFPNDEF(const char *cmd) {
|
||||||
|
|
||||||
NDEFDecodeAndPrint(data, datalen, verbose);
|
NDEFDecodeAndPrint(data, datalen, verbose);
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
|
@ -845,6 +1173,7 @@ static command_t CommandTable[] = {
|
||||||
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"},
|
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"},
|
||||||
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"},
|
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"},
|
||||||
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"},
|
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"},
|
||||||
|
{"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"},
|
||||||
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Checks and prints MAD"},
|
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Checks and prints MAD"},
|
||||||
{"ndef", CmdHFMFPNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
{"ndef", CmdHFMFPNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
|
@ -853,7 +1182,7 @@ static command_t CommandTable[] = {
|
||||||
static int CmdHelp(const char *Cmd) {
|
static int CmdHelp(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
CmdsHelp(CommandTable);
|
CmdsHelp(CommandTable);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdHFMFP(const char *Cmd) {
|
int CmdHFMFP(const char *Cmd) {
|
||||||
|
|
|
@ -445,7 +445,7 @@ static int ul_ev1_pwdgen_selftest() {
|
||||||
uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80};
|
uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80};
|
||||||
uint32_t pwd4 = ul_ev1_pwdgenD(uid4);
|
uint32_t pwd4 = ul_ev1_pwdgenD(uid4);
|
||||||
PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, (pwd4 == 0x72B1EC61) ? "OK" : "->72B1EC61<--");
|
PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, (pwd4 == 0x72B1EC61) ? "OK" : "->72B1EC61<--");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
@ -565,7 +565,7 @@ static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) {
|
||||||
static int ulc_authentication(uint8_t *key, bool switch_off_field) {
|
static int ulc_authentication(uint8_t *key, bool switch_off_field) {
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16);
|
SendCommandMIX(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 0;
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 0;
|
||||||
if (resp.oldarg[0] == 1) return 1;
|
if (resp.oldarg[0] == 1) return 1;
|
||||||
|
@ -2262,7 +2262,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4));
|
PrintAndLogEx(NORMAL, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data));
|
||||||
|
|
||||||
wait4response(MFU_NTAG_SPECIAL_PWD);
|
wait4response(MFU_NTAG_SPECIAL_PWD);
|
||||||
|
|
||||||
|
@ -2278,7 +2278,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
data[3] = 0;
|
data[3] = 0;
|
||||||
PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4));
|
PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data));
|
||||||
wait4response(MFU_NTAG_SPECIAL_PACK);
|
wait4response(MFU_NTAG_SPECIAL_PACK);
|
||||||
|
|
||||||
// Signature
|
// Signature
|
||||||
|
@ -2286,7 +2286,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
memcpy(data, mem->signature + i, 4);
|
memcpy(data, mem->signature + i, 4);
|
||||||
PrintAndLogEx(NORMAL, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4));
|
PrintAndLogEx(NORMAL, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
||||||
wait4response(s);
|
wait4response(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2295,7 +2295,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
memcpy(data, mem->version + i, 4);
|
memcpy(data, mem->version + i, 4);
|
||||||
PrintAndLogEx(NORMAL, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4));
|
PrintAndLogEx(NORMAL, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
||||||
wait4response(s);
|
wait4response(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2309,7 +2309,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
//Send write Block
|
//Send write Block
|
||||||
memcpy(data, mem->data + (b * 4), 4);
|
memcpy(data, mem->data + (b * 4), 4);
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data));
|
||||||
wait4response(b);
|
wait4response(b);
|
||||||
printf(".");
|
printf(".");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -2329,7 +2329,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
uint8_t b = blocks[i];
|
uint8_t b = blocks[i];
|
||||||
memcpy(data, mem->data + (b * 4), 4);
|
memcpy(data, mem->data + (b * 4), 4);
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data));
|
||||||
wait4response(b);
|
wait4response(b);
|
||||||
PrintAndLogEx(NORMAL, "special block written %u - %s\n", b, sprint_hex(data, 4));
|
PrintAndLogEx(NORMAL, "special block written %u - %s\n", b, sprint_hex(data, 4));
|
||||||
}
|
}
|
||||||
|
@ -2338,7 +2338,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
free(dump);
|
free(dump);
|
||||||
PrintAndLogEx(INFO, "Finish restore");
|
PrintAndLogEx(INFO, "Finish restore");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Load emulator with dump file
|
// Load emulator with dump file
|
||||||
|
@ -2388,7 +2388,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||||
else
|
else
|
||||||
PrintAndLogEx(WARNING, "Authentication failed");
|
PrintAndLogEx(WARNING, "Authentication failed");
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2500,11 +2500,11 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) {
|
||||||
|
|
||||||
if (param_gethex(Cmd, 0, pwd, 32)) {
|
if (param_gethex(Cmd, 0, pwd, 32)) {
|
||||||
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
|
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
|
||||||
return 1;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16);
|
SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16);
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
|
@ -2512,13 +2512,13 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd, 16));
|
PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd, 16));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xff));
|
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xff));
|
||||||
return 1;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execution time out");
|
||||||
return 1;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -2556,7 +2556,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
data[2] = uid[2];
|
data[2] = uid[2];
|
||||||
data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
|
data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
|
@ -2568,7 +2568,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
data[2] = uid[5];
|
data[2] = uid[5];
|
||||||
data[3] = uid[6];
|
data[3] = uid[6];
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
|
@ -2580,7 +2580,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
data[2] = oldblock2[2];
|
data[2] = oldblock2[2];
|
||||||
data[3] = oldblock2[3];
|
data[3] = oldblock2[3];
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
|
@ -2611,11 +2611,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
|
||||||
|
|
||||||
if (select_status == 0) {
|
if (select_status == 0) {
|
||||||
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||||
return 1;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
if (card.uidlen != 4) {
|
if (card.uidlen != 4) {
|
||||||
PrintAndLogEx(WARNING, "Wrong sized UID, expected 4bytes got %d", card.uidlen);
|
PrintAndLogEx(WARNING, "Wrong sized UID, expected 4bytes got %d", card.uidlen);
|
||||||
return 1;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
memcpy(uid, card.uid, sizeof(uid));
|
memcpy(uid, card.uid, sizeof(uid));
|
||||||
} else {
|
} else {
|
||||||
|
@ -2654,13 +2654,13 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
|
||||||
, divkey // output
|
, divkey // output
|
||||||
);
|
);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "-- 3DES version");
|
PrintAndLogEx(SUCCESS, "-- 3DES version");
|
||||||
PrintAndLogEx(NORMAL, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey)));
|
PrintAndLogEx(SUCCESS, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey)));
|
||||||
PrintAndLogEx(NORMAL, "UID :\t %s", sprint_hex(uid, sizeof(uid)));
|
PrintAndLogEx(SUCCESS, "UID :\t %s", sprint_hex(uid, sizeof(uid)));
|
||||||
PrintAndLogEx(NORMAL, "block :\t %0d", block);
|
PrintAndLogEx(SUCCESS, "block :\t %0d", block);
|
||||||
PrintAndLogEx(NORMAL, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA)));
|
PrintAndLogEx(SUCCESS, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA)));
|
||||||
PrintAndLogEx(NORMAL, "Message :\t %s", sprint_hex(mix, sizeof(mix)));
|
PrintAndLogEx(SUCCESS, "Message :\t %s", sprint_hex(mix, sizeof(mix)));
|
||||||
PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey + 1, 6));
|
PrintAndLogEx(SUCCESS, "Diversified key: %s", sprint_hex(divkey + 1, 6));
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYLEN(mifarekeyA); ++i) {
|
for (int i = 0; i < ARRAYLEN(mifarekeyA); ++i) {
|
||||||
dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
|
dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
|
||||||
|
@ -2690,11 +2690,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
|
||||||
, newpwd // output
|
, newpwd // output
|
||||||
);
|
);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "\n-- DES version");
|
PrintAndLogEx(SUCCESS, "\n-- DES version");
|
||||||
PrintAndLogEx(NORMAL, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA)));
|
PrintAndLogEx(SUCCESS, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA)));
|
||||||
PrintAndLogEx(NORMAL, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB)));
|
PrintAndLogEx(SUCCESS, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB)));
|
||||||
PrintAndLogEx(NORMAL, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey)));
|
PrintAndLogEx(SUCCESS, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey)));
|
||||||
PrintAndLogEx(NORMAL, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd)));
|
PrintAndLogEx(SUCCESS, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd)));
|
||||||
|
|
||||||
mbedtls_des3_free(&ctx);
|
mbedtls_des3_free(&ctx);
|
||||||
// next. from the diversify_key method.
|
// next. from the diversify_key method.
|
||||||
|
|
|
@ -220,14 +220,14 @@ static int topaz_print_CC(uint8_t *data) {
|
||||||
return PM3_ESOFT; // no NDEF message
|
return PM3_ESOFT; // no NDEF message
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
|
PrintAndLogEx(SUCCESS, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
|
||||||
PrintAndLogEx(NORMAL, " %02x: NDEF Magic Number", data[0]);
|
PrintAndLogEx(SUCCESS, " %02x: NDEF Magic Number", data[0]);
|
||||||
PrintAndLogEx(NORMAL, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
|
PrintAndLogEx(SUCCESS, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
|
||||||
uint16_t memsize = (data[2] + 1) * 8;
|
uint16_t memsize = (data[2] + 1) * 8;
|
||||||
topaz_tag.size = memsize;
|
topaz_tag.size = memsize;
|
||||||
topaz_tag.dynamic_memory = calloc(memsize - TOPAZ_STATIC_MEMORY, sizeof(uint8_t));
|
topaz_tag.dynamic_memory = calloc(memsize - TOPAZ_STATIC_MEMORY, sizeof(uint8_t));
|
||||||
PrintAndLogEx(NORMAL, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize);
|
PrintAndLogEx(SUCCESS, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize);
|
||||||
PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3],
|
PrintAndLogEx(SUCCESS, " %02x: %s / %s", data[3],
|
||||||
(data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security",
|
(data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security",
|
||||||
(data[3] & 0x0F) == 0 ? "Write access granted without any security" : (data[3] & 0x0F) == 0x0F ? "No write access granted at all" : "(RFU)");
|
(data[3] & 0x0F) == 0 ? "Write access granted without any security" : (data[3] & 0x0F) == 0x0F ? "No write access granted at all" : "(RFU)");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -301,7 +301,7 @@ static void topaz_print_control_TLVs(uint8_t *memory) {
|
||||||
uint16_t bytes_per_page = 1 << (TLV_value[2] & 0x0f);
|
uint16_t bytes_per_page = 1 << (TLV_value[2] & 0x0f);
|
||||||
uint16_t bytes_locked_per_bit = 1 << (TLV_value[2] >> 4);
|
uint16_t bytes_locked_per_bit = 1 << (TLV_value[2] >> 4);
|
||||||
uint16_t area_start = pages_addr * bytes_per_page + byte_offset;
|
uint16_t area_start = pages_addr * bytes_per_page + byte_offset;
|
||||||
PrintAndLogEx(NORMAL, "Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.",
|
PrintAndLogEx(SUCCESS, "Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.",
|
||||||
size_in_bits,
|
size_in_bits,
|
||||||
area_start,
|
area_start,
|
||||||
bytes_locked_per_bit);
|
bytes_locked_per_bit);
|
||||||
|
@ -333,7 +333,7 @@ static void topaz_print_control_TLVs(uint8_t *memory) {
|
||||||
uint16_t size_in_bytes = TLV_value[1] ? TLV_value[1] : 256;
|
uint16_t size_in_bytes = TLV_value[1] ? TLV_value[1] : 256;
|
||||||
uint8_t bytes_per_page = 1 << (TLV_value[2] & 0x0f);
|
uint8_t bytes_per_page = 1 << (TLV_value[2] & 0x0f);
|
||||||
uint16_t area_start = pages_addr * bytes_per_page + byte_offset;
|
uint16_t area_start = pages_addr * bytes_per_page + byte_offset;
|
||||||
PrintAndLogEx(NORMAL, "Reserved Memory of %d bytes at byte offset 0x%02x.",
|
PrintAndLogEx(SUCCESS, "Reserved Memory of %d bytes at byte offset 0x%02x.",
|
||||||
size_in_bytes,
|
size_in_bytes,
|
||||||
area_start);
|
area_start);
|
||||||
reserved_memory_control_TLV_present = true;
|
reserved_memory_control_TLV_present = true;
|
||||||
|
@ -345,11 +345,11 @@ static void topaz_print_control_TLVs(uint8_t *memory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lock_TLV_present) {
|
if (!lock_TLV_present) {
|
||||||
PrintAndLogEx(NORMAL, "(No Lock Control TLV present)");
|
PrintAndLogEx(SUCCESS, "(No Lock Control TLV present)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reserved_memory_control_TLV_present) {
|
if (!reserved_memory_control_TLV_present) {
|
||||||
PrintAndLogEx(NORMAL, "(No Reserved Memory Control TLV present)");
|
PrintAndLogEx(SUCCESS, "(No Reserved Memory Control TLV present)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ static int topaz_read_dynamic_data(void) {
|
||||||
// read and print the dynamic memory
|
// read and print the dynamic memory
|
||||||
static void topaz_print_dynamic_data(void) {
|
static void topaz_print_dynamic_data(void) {
|
||||||
if (topaz_tag.size > TOPAZ_STATIC_MEMORY) {
|
if (topaz_tag.size > TOPAZ_STATIC_MEMORY) {
|
||||||
PrintAndLogEx(NORMAL, "Dynamic Data blocks:");
|
PrintAndLogEx(SUCCESS, "Dynamic Data blocks:");
|
||||||
if (topaz_read_dynamic_data() == 0) {
|
if (topaz_read_dynamic_data() == 0) {
|
||||||
PrintAndLogEx(NORMAL, "block# | offset | Data | Locked(y/n)");
|
PrintAndLogEx(NORMAL, "block# | offset | Data | Locked(y/n)");
|
||||||
PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------");
|
PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------");
|
||||||
|
@ -435,19 +435,19 @@ static int CmdHFTopazReader(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", atqa[1], atqa[0]);
|
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", atqa[1], atqa[0]);
|
||||||
|
|
||||||
topaz_tag.HR01[0] = rid_response[0];
|
topaz_tag.HR01[0] = rid_response[0];
|
||||||
topaz_tag.HR01[1] = rid_response[1];
|
topaz_tag.HR01[1] = rid_response[1];
|
||||||
|
|
||||||
// ToDo: CRC check
|
// ToDo: CRC check
|
||||||
PrintAndLogEx(NORMAL, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)",
|
PrintAndLogEx(SUCCESS, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)",
|
||||||
rid_response[0],
|
rid_response[0],
|
||||||
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
||||||
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
||||||
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic");
|
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic");
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "HR1 : %02x", rid_response[1]);
|
PrintAndLogEx(SUCCESS, "HR1 : %02x", rid_response[1]);
|
||||||
|
|
||||||
status = topaz_rall(uid_echo, rall_response);
|
status = topaz_rall(uid_echo, rall_response);
|
||||||
|
|
||||||
|
@ -458,7 +458,7 @@ static int CmdHFTopazReader(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(topaz_tag.uid, rall_response + 2, 7);
|
memcpy(topaz_tag.uid, rall_response + 2, 7);
|
||||||
PrintAndLogEx(NORMAL, "UID : %02x %02x %02x %02x %02x %02x %02x",
|
PrintAndLogEx(SUCCESS, "UID : %02x %02x %02x %02x %02x %02x %02x",
|
||||||
topaz_tag.uid[6],
|
topaz_tag.uid[6],
|
||||||
topaz_tag.uid[5],
|
topaz_tag.uid[5],
|
||||||
topaz_tag.uid[4],
|
topaz_tag.uid[4],
|
||||||
|
@ -467,13 +467,13 @@ static int CmdHFTopazReader(const char *Cmd) {
|
||||||
topaz_tag.uid[1],
|
topaz_tag.uid[1],
|
||||||
topaz_tag.uid[0]);
|
topaz_tag.uid[0]);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"),
|
PrintAndLogEx(SUCCESS, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"),
|
||||||
topaz_tag.uid[6],
|
topaz_tag.uid[6],
|
||||||
getTagInfo(topaz_tag.uid[6]));
|
getTagInfo(topaz_tag.uid[6]));
|
||||||
|
|
||||||
memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8);
|
memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8);
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":");
|
PrintAndLogEx(SUCCESS, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":");
|
||||||
PrintAndLogEx(NORMAL, "block# | offset | Data | Locked");
|
PrintAndLogEx(NORMAL, "block# | offset | Data | Locked");
|
||||||
PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------");
|
PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------");
|
||||||
char line[80];
|
char line[80];
|
||||||
|
@ -488,7 +488,7 @@ static int CmdHFTopazReader(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "Static Reserved block " _YELLOW_("0x0D")":");
|
PrintAndLogEx(SUCCESS, "Static Reserved block " _YELLOW_("0x0D")":");
|
||||||
for (uint16_t j = 0; j < 8; j++) {
|
for (uint16_t j = 0; j < 8; j++) {
|
||||||
sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0d][j]);
|
sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0d][j]);
|
||||||
}
|
}
|
||||||
|
@ -496,7 +496,7 @@ static int CmdHFTopazReader(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, " 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d * 8, line, "n/a");
|
PrintAndLogEx(NORMAL, " 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d * 8, line, "n/a");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Static Lockbits and OTP Bytes:");
|
PrintAndLogEx(SUCCESS, "Static Lockbits and OTP Bytes:");
|
||||||
for (uint16_t j = 0; j < 8; j++) {
|
for (uint16_t j = 0; j < 8; j++) {
|
||||||
sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0e][j]);
|
sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0e][j]);
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ static int CmdHFTopazReader(const char *Cmd) {
|
||||||
status = topaz_print_CC(&topaz_tag.data_blocks[1][0]);
|
status = topaz_print_CC(&topaz_tag.data_blocks[1][0]);
|
||||||
|
|
||||||
if (status == PM3_ESOFT) {
|
if (status == PM3_ESOFT) {
|
||||||
PrintAndLogEx(NORMAL, "No NDEF message data present");
|
PrintAndLogEx(SUCCESS, "No NDEF message data present");
|
||||||
topaz_switch_off_field();
|
topaz_switch_off_field();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -528,13 +528,13 @@ static int CmdHFTopazReader(const char *Cmd) {
|
||||||
|
|
||||||
static int CmdHFTopazSim(const char *Cmd) {
|
static int CmdHFTopazSim(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
PrintAndLogEx(NORMAL, "not yet implemented");
|
PrintAndLogEx(INFO, "not yet implemented");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFTopazCmdRaw(const char *Cmd) {
|
static int CmdHFTopazCmdRaw(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
PrintAndLogEx(NORMAL, "not yet implemented. Use hf 14 raw with option -T.");
|
PrintAndLogEx(INFO, "not yet implemented. Use hf 14 raw with option -T.");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||||
char asBuff[120];
|
char asBuff[120];
|
||||||
memset(asBuff, 0, sizeof(asBuff));
|
memset(asBuff, 0, sizeof(asBuff));
|
||||||
uint32_t mem_avail = 0;
|
uint32_t mem_avail = 0;
|
||||||
PrintAndLogEx(NORMAL, "\n [ Hardware ] ");
|
PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Hardware ]"));
|
||||||
|
|
||||||
switch (iChipID) {
|
switch (iChipID) {
|
||||||
case 0x270B0A40:
|
case 0x270B0A40:
|
||||||
|
@ -447,13 +447,13 @@ static int CmdSetDivisor(const char *Cmd) {
|
||||||
uint8_t arg = param_get8ex(Cmd, 0, 95, 10);
|
uint8_t arg = param_get8ex(Cmd, 0, 95, 10);
|
||||||
|
|
||||||
if (arg < 19) {
|
if (arg < 19) {
|
||||||
PrintAndLogEx(ERR, "divisor must be between 19 and 255");
|
PrintAndLogEx(ERR, "divisor must be between" _YELLOW_("19") " and " _YELLOW_("255") );
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
// 12 000 000 (12MHz)
|
// 12 000 000 (12MHz)
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_SET_DIVISOR, (uint8_t *)&arg, sizeof(arg));
|
SendCommandNG(CMD_LF_SET_DIVISOR, (uint8_t *)&arg, sizeof(arg));
|
||||||
PrintAndLogEx(SUCCESS, "Divisor set, expected %.1f kHz", ((double)12000 / (arg + 1)));
|
PrintAndLogEx(SUCCESS, "Divisor set, expected " _YELLOW_("%.1f")" kHz", ((double)12000 / (arg + 1)));
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,11 +514,11 @@ static int CmdStatus(const char *Cmd) {
|
||||||
static int CmdTia(const char *Cmd) {
|
static int CmdTia(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition...");
|
PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)...");
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
SendCommandNG(CMD_TIA, NULL, 0);
|
SendCommandNG(CMD_TIA, NULL, 0);
|
||||||
if (WaitForResponseTimeout(CMD_TIA, &resp, 2000) == false)
|
if (WaitForResponseTimeout(CMD_TIA, &resp, 2000) == false)
|
||||||
PrintAndLogEx(WARNING, "Tia command failed. You probably need to unplug the Proxmark3.");
|
PrintAndLogEx(WARNING, "TIA command failed. You probably need to unplug the Proxmark3.");
|
||||||
PrintAndLogEx(INFO, "TIA done.");
|
PrintAndLogEx(INFO, "TIA done.");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -528,7 +528,7 @@ static int CmdPing(const char *Cmd) {
|
||||||
if (len > PM3_CMD_DATA_SIZE)
|
if (len > PM3_CMD_DATA_SIZE)
|
||||||
len = PM3_CMD_DATA_SIZE;
|
len = PM3_CMD_DATA_SIZE;
|
||||||
if (len) {
|
if (len) {
|
||||||
PrintAndLogEx(INFO, "Ping sent with payload len=%d", len);
|
PrintAndLogEx(INFO, "Ping sent with payload len = %d", len);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "Ping sent");
|
PrintAndLogEx(INFO, "Ping sent");
|
||||||
}
|
}
|
||||||
|
@ -702,26 +702,24 @@ void pm3_version(bool verbose, bool oneliner) {
|
||||||
SendCommandNG(CMD_VERSION, NULL, 0);
|
SendCommandNG(CMD_VERSION, NULL, 0);
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) {
|
if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) {
|
||||||
PrintAndLogEx(NORMAL, "\n" _BLUE_(" [ Proxmark3 RFID instrument ]") "\n");
|
PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Proxmark3 RFID instrument ]"));
|
||||||
PrintAndLogEx(NORMAL, "\n [ CLIENT ]");
|
PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ CLIENT ]"));
|
||||||
PrintAndLogEx(NORMAL, " client: RRG/Iceman"); // TODO version info?
|
PrintAndLogEx(NORMAL, " client: RRG/Iceman"); // TODO version info?
|
||||||
PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH);
|
PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH);
|
||||||
|
|
||||||
//#if PLATFORM == PM3RDV4
|
|
||||||
if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) {
|
if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) {
|
||||||
PrintAndLogEx(NORMAL, "\n [ PROXMARK3 ]");
|
PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 ]"));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, "\n [ PROXMARK3 RDV4 ]");
|
PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 RDV4 ]"));
|
||||||
PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||||
PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||||
PrintAndLogEx(NORMAL, "\n [ PROXMARK3 RDV4 Extras ]");
|
PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 RDV4 Extras ]"));
|
||||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||||
|
|
||||||
if (IfPm3FpcUsartDevFromUsb()) {
|
if (IfPm3FpcUsartDevFromUsb()) {
|
||||||
PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present"));
|
PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//#endif
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
|
|
|
@ -798,7 +798,7 @@ int CmdLFfskSim(const char *Cmd) {
|
||||||
|
|
||||||
size_t size = DemodBufferLen;
|
size_t size = DemodBufferLen;
|
||||||
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t))) {
|
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t))) {
|
||||||
PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t));
|
PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t));
|
||||||
size = PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t);
|
size = PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -900,7 +900,7 @@ int CmdLFaskSim(const char *Cmd) {
|
||||||
|
|
||||||
size_t size = DemodBufferLen;
|
size_t size = DemodBufferLen;
|
||||||
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t))) {
|
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t))) {
|
||||||
PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t));
|
PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t));
|
||||||
size = PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t);
|
size = PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,13 +993,13 @@ int CmdLFpskSim(const char *Cmd) {
|
||||||
if (errors) return usage_lf_simpsk();
|
if (errors) return usage_lf_simpsk();
|
||||||
|
|
||||||
if (dataLen == 0) { //using DemodBuffer
|
if (dataLen == 0) { //using DemodBuffer
|
||||||
PrintAndLogEx(NORMAL, "Getting Clocks");
|
PrintAndLogEx(INFO, "Getting Clocks");
|
||||||
|
|
||||||
if (clk == 0) clk = GetPskClock("", false);
|
if (clk == 0) clk = GetPskClock("", false);
|
||||||
PrintAndLogEx(NORMAL, "clk: %d", clk);
|
PrintAndLogEx(INFO, "clk: %d", clk);
|
||||||
|
|
||||||
if (!carrier) carrier = GetPskCarrier("", false);
|
if (!carrier) carrier = GetPskCarrier("", false);
|
||||||
PrintAndLogEx(NORMAL, "carrier: %d", carrier);
|
PrintAndLogEx(INFO, "carrier: %d", carrier);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
setDemodBuff(data, dataLen, 0);
|
setDemodBuff(data, dataLen, 0);
|
||||||
|
@ -1015,12 +1015,12 @@ int CmdLFpskSim(const char *Cmd) {
|
||||||
//need to convert psk2 to psk1 data before sim
|
//need to convert psk2 to psk1 data before sim
|
||||||
psk2TOpsk1(DemodBuffer, DemodBufferLen);
|
psk2TOpsk1(DemodBuffer, DemodBufferLen);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, "Sorry, PSK3 not yet available");
|
PrintAndLogEx(WARNING, "Sorry, PSK3 not yet available");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t size = DemodBufferLen;
|
size_t size = DemodBufferLen;
|
||||||
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t))) {
|
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t))) {
|
||||||
PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t));
|
PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t));
|
||||||
size = PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t);
|
size = PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "cmdlfnexwatch.h"
|
#include "cmdlfnexwatch.h"
|
||||||
|
#include <inttypes.h> // PRIu
|
||||||
#include <ctype.h> // tolower
|
#include <ctype.h> // tolower
|
||||||
|
|
||||||
#include "commonutil.h" // ARRAYLEN
|
#include "commonutil.h" // ARRAYLEN
|
||||||
|
@ -80,9 +81,9 @@ static int CmdNexWatchDemod(const char *Cmd) {
|
||||||
//checksum check (TBD)
|
//checksum check (TBD)
|
||||||
|
|
||||||
//output
|
//output
|
||||||
PrintAndLogEx(NORMAL, "NexWatch ID: %d", ID);
|
PrintAndLogEx(SUCCESS, "NexWatch ID: " _YELLOW_("%"PRIu32) , ID);
|
||||||
if (invert) {
|
if (invert) {
|
||||||
PrintAndLogEx(NORMAL, "Had to Invert - probably NexKey");
|
PrintAndLogEx(INFO, "Had to Invert - probably NexKey");
|
||||||
for (size_t i = 0; i < size; i++)
|
for (size_t i = 0; i < size; i++)
|
||||||
DemodBuffer[i] ^= 1;
|
DemodBuffer[i] ^= 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,21 +50,21 @@ static int usage_trace_list() {
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " trace list 14a f");
|
PrintAndLogEx(NORMAL, " trace list 14a f");
|
||||||
PrintAndLogEx(NORMAL, " trace list iclass");
|
PrintAndLogEx(NORMAL, " trace list iclass");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
static int usage_trace_load() {
|
static int usage_trace_load() {
|
||||||
PrintAndLogEx(NORMAL, "Load protocol data from file to trace buffer.");
|
PrintAndLogEx(NORMAL, "Load protocol data from file to trace buffer.");
|
||||||
PrintAndLogEx(NORMAL, "Usage: trace load <filename>");
|
PrintAndLogEx(NORMAL, "Usage: trace load <filename>");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " trace load mytracefile.bin");
|
PrintAndLogEx(NORMAL, " trace load mytracefile.bin");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
static int usage_trace_save() {
|
static int usage_trace_save() {
|
||||||
PrintAndLogEx(NORMAL, "Save protocol data from trace buffer to file.");
|
PrintAndLogEx(NORMAL, "Save protocol data from trace buffer to file.");
|
||||||
PrintAndLogEx(NORMAL, "Usage: trace save <filename>");
|
PrintAndLogEx(NORMAL, "Usage: trace save <filename>");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " trace save mytracefile.bin");
|
PrintAndLogEx(NORMAL, " trace save mytracefile.bin");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) {
|
static bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) {
|
||||||
|
@ -450,7 +450,7 @@ static int CmdTraceLoad(const char *Cmd) {
|
||||||
|
|
||||||
if ((f = fopen(filename, "rb")) == NULL) {
|
if ((f = fopen(filename, "rb")) == NULL) {
|
||||||
PrintAndLogEx(FAILED, "Could not open file " _YELLOW_("%s"), filename);
|
PrintAndLogEx(FAILED, "Could not open file " _YELLOW_("%s"), filename);
|
||||||
return 0;
|
return PM3_EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get filesize in order to malloc memory
|
// get filesize in order to malloc memory
|
||||||
|
@ -461,12 +461,12 @@ static int CmdTraceLoad(const char *Cmd) {
|
||||||
if (fsize < 0) {
|
if (fsize < 0) {
|
||||||
PrintAndLogEx(FAILED, "error, when getting filesize");
|
PrintAndLogEx(FAILED, "error, when getting filesize");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 3;
|
return PM3_EIO;
|
||||||
}
|
}
|
||||||
if (fsize < 4) {
|
if (fsize < 4) {
|
||||||
PrintAndLogEx(FAILED, "error, file is too small");
|
PrintAndLogEx(FAILED, "error, file is too small");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 4;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trace)
|
if (trace)
|
||||||
|
@ -476,21 +476,21 @@ static int CmdTraceLoad(const char *Cmd) {
|
||||||
if (!trace) {
|
if (!trace) {
|
||||||
PrintAndLogEx(FAILED, "Cannot allocate memory for trace");
|
PrintAndLogEx(FAILED, "Cannot allocate memory for trace");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 2;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytes_read = fread(trace, 1, fsize, f);
|
size_t bytes_read = fread(trace, 1, fsize, f);
|
||||||
traceLen = bytes_read;
|
traceLen = bytes_read;
|
||||||
fclose(f);
|
fclose(f);
|
||||||
PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes) loaded from file %s", traceLen, filename);
|
PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes) loaded from file %s", traceLen, filename);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdTraceSave(const char *Cmd) {
|
static int CmdTraceSave(const char *Cmd) {
|
||||||
|
|
||||||
if (traceLen == 0) {
|
if (traceLen == 0) {
|
||||||
PrintAndLogEx(WARNING, "trace is empty, nothing to save");
|
PrintAndLogEx(WARNING, "trace is empty, nothing to save");
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
char filename[FILE_PATH_SIZE];
|
char filename[FILE_PATH_SIZE];
|
||||||
|
@ -499,7 +499,7 @@ static int CmdTraceSave(const char *Cmd) {
|
||||||
|
|
||||||
param_getstr(Cmd, 0, filename, sizeof(filename));
|
param_getstr(Cmd, 0, filename, sizeof(filename));
|
||||||
saveFile(filename, ".bin", trace, traceLen);
|
saveFile(filename, ".bin", trace, traceLen);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
|
@ -513,7 +513,7 @@ static command_t CommandTable[] = {
|
||||||
static int CmdHelp(const char *Cmd) {
|
static int CmdHelp(const char *Cmd) {
|
||||||
(void)Cmd; // Cmd is not used so far
|
(void)Cmd; // Cmd is not used so far
|
||||||
CmdsHelp(CommandTable);
|
CmdsHelp(CommandTable);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdTrace(const char *Cmd) {
|
int CmdTrace(const char *Cmd) {
|
||||||
|
@ -604,15 +604,20 @@ int CmdTraceList(const char *Cmd) {
|
||||||
uint16_t tracepos = 0;
|
uint16_t tracepos = 0;
|
||||||
|
|
||||||
// reserv some space.
|
// reserv some space.
|
||||||
if (!trace)
|
if (!trace) {
|
||||||
trace = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
trace = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||||
|
if (trace == NULL) {
|
||||||
|
PrintAndLogEx(FAILED, "Cannot allocate memory for trace");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isOnline) {
|
if (isOnline) {
|
||||||
// Query for the size of the trace, downloading PM3_CMD_DATA_SIZE
|
// Query for the size of the trace, downloading PM3_CMD_DATA_SIZE
|
||||||
PacketResponseNG response;
|
PacketResponseNG response;
|
||||||
if (!GetFromDevice(BIG_BUF, trace, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 4000, true)) {
|
if (!GetFromDevice(BIG_BUF, trace, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 4000, true)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
return 1;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
traceLen = response.oldarg[2];
|
traceLen = response.oldarg[2];
|
||||||
|
@ -621,13 +626,13 @@ int CmdTraceList(const char *Cmd) {
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
PrintAndLogEx(FAILED, "Cannot allocate memory for trace");
|
PrintAndLogEx(FAILED, "Cannot allocate memory for trace");
|
||||||
free(trace);
|
free(trace);
|
||||||
return 2;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
trace = p;
|
trace = p;
|
||||||
if (!GetFromDevice(BIG_BUF, trace, traceLen, 0, NULL, 0, NULL, 2500, false)) {
|
if (!GetFromDevice(BIG_BUF, trace, traceLen, 0, NULL, 0, NULL, 2500, false)) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execution time out");
|
||||||
free(trace);
|
free(trace);
|
||||||
return 3;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -678,6 +683,6 @@ int CmdTraceList(const char *Cmd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
27
client/dictionaries/mfp_default_keys.dic
Normal file
27
client/dictionaries/mfp_default_keys.dic
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
ffffffffffffffffffffffffffffffff
|
||||||
|
00000000000000000000000000000000
|
||||||
|
a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7
|
||||||
|
b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7
|
||||||
|
d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7
|
||||||
|
11111111111111111111111111111111
|
||||||
|
22222222222222222222222222222222
|
||||||
|
33333333333333333333333333333333
|
||||||
|
44444444444444444444444444444444
|
||||||
|
55555555555555555555555555555555
|
||||||
|
66666666666666666666666666666666
|
||||||
|
77777777777777777777777777777777
|
||||||
|
88888888888888888888888888888888
|
||||||
|
99999999999999999999999999999999
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||||
|
cccccccccccccccccccccccccccccccc
|
||||||
|
dddddddddddddddddddddddddddddddd
|
||||||
|
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||||
|
000102030405060708090a0b0c0d0e0f
|
||||||
|
0102030405060708090a0b0c0d0e0f10
|
||||||
|
00010203040506070809101112131415
|
||||||
|
01020304050607080910111213141516
|
||||||
|
16151413121110090807060504030201
|
||||||
|
15141312111009080706050403020100
|
||||||
|
0f0e0d0c0b0a09080706050403020100
|
||||||
|
100f0e0d0c0b0a090807060504030201
|
|
@ -352,6 +352,34 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s
|
||||||
case jsf15:
|
case jsf15:
|
||||||
case jsfLegic:
|
case jsfLegic:
|
||||||
case jsfT5555:
|
case jsfT5555:
|
||||||
|
case jsfMfPlusKeys:
|
||||||
|
JsonSaveStr(root, "FileType", "mfp");
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2);
|
||||||
|
uint8_t atslen = data[13];
|
||||||
|
if (atslen > 0)
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen);
|
||||||
|
|
||||||
|
uint8_t vdata[2][64][16 + 1] = {{{0}}};
|
||||||
|
memcpy(vdata, &data[14 + atslen], 2 * 64 * 17);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < datalen; i++) {
|
||||||
|
char path[PATH_MAX_LENGTH] = {0};
|
||||||
|
|
||||||
|
if (vdata[0][i][0]) {
|
||||||
|
memset(path, 0x00, sizeof(path));
|
||||||
|
sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i));
|
||||||
|
JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vdata[1][i][0]) {
|
||||||
|
memset(path, 0x00, sizeof(path));
|
||||||
|
sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i));
|
||||||
|
JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -715,20 +743,29 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt) {
|
int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt) {
|
||||||
|
// t5577 == 4bytes
|
||||||
|
// mifare == 6 bytes
|
||||||
|
// mf plus == 16 bytes
|
||||||
|
// iclass == 8 bytes
|
||||||
|
// default to 6 bytes.
|
||||||
|
if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) {
|
||||||
|
keylen = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt,
|
||||||
|
size_t startFilePosition, size_t *endFilePosition, bool verbose) {
|
||||||
|
if (endFilePosition)
|
||||||
|
*endFilePosition = 0;
|
||||||
if (data == NULL) return PM3_EINVARG;
|
if (data == NULL) return PM3_EINVARG;
|
||||||
|
uint16_t vkeycnt = 0;
|
||||||
|
|
||||||
char *path;
|
char *path;
|
||||||
if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS)
|
if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS)
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
|
|
||||||
// t5577 == 4bytes
|
|
||||||
// mifare == 6 bytes
|
|
||||||
// iclass == 8 bytes
|
|
||||||
// default to 6 bytes.
|
|
||||||
if (keylen != 4 && keylen != 6 && keylen != 8) {
|
|
||||||
keylen = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
// double up since its chars
|
// double up since its chars
|
||||||
keylen <<= 1;
|
keylen <<= 1;
|
||||||
|
|
||||||
|
@ -744,8 +781,17 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (startFilePosition)
|
||||||
|
fseek(f, startFilePosition, SEEK_SET);
|
||||||
|
|
||||||
// read file
|
// read file
|
||||||
while (fgets(line, sizeof(line), f)) {
|
while (!feof(f)) {
|
||||||
|
size_t filepos = ftell(f);
|
||||||
|
if (!fgets(line, sizeof(line), f)) {
|
||||||
|
if (endFilePosition)
|
||||||
|
*endFilePosition = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// add null terminator
|
// add null terminator
|
||||||
line[keylen] = 0;
|
line[keylen] = 0;
|
||||||
|
@ -758,23 +804,32 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u
|
||||||
if (line[0] == '#')
|
if (line[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!isxdigit(line[0])) {
|
if (!CheckStringIsHEXValue(line))
|
||||||
PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen);
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// cant store more data
|
||||||
|
if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) {
|
||||||
|
retval = 1;
|
||||||
|
if (endFilePosition)
|
||||||
|
*endFilePosition = filepos;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t key = strtoull(line, NULL, 16);
|
if (hex_to_bytes(line, data + counter, keylen >> 1) != (keylen >> 1))
|
||||||
|
continue;
|
||||||
|
|
||||||
num_to_bytes(key, keylen >> 1, data + counter);
|
vkeycnt++;
|
||||||
(*keycnt)++;
|
|
||||||
memset(line, 0, sizeof(line));
|
memset(line, 0, sizeof(line));
|
||||||
counter += (keylen >> 1);
|
counter += (keylen >> 1);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), *keycnt, path);
|
if (verbose)
|
||||||
|
PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path);
|
||||||
|
|
||||||
if (datalen)
|
if (datalen)
|
||||||
*datalen = counter;
|
*datalen = counter;
|
||||||
|
if (keycnt)
|
||||||
|
*keycnt = vkeycnt;
|
||||||
out:
|
out:
|
||||||
free(path);
|
free(path);
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -790,9 +845,10 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key
|
||||||
|
|
||||||
// t5577 == 4bytes
|
// t5577 == 4bytes
|
||||||
// mifare == 6 bytes
|
// mifare == 6 bytes
|
||||||
|
// mf plus == 16 bytes
|
||||||
// iclass == 8 bytes
|
// iclass == 8 bytes
|
||||||
// default to 6 bytes.
|
// default to 6 bytes.
|
||||||
if (keylen != 4 && keylen != 6 && keylen != 8) {
|
if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) {
|
||||||
keylen = 6;
|
keylen = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,10 +904,8 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key
|
||||||
if (line[0] == '#')
|
if (line[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!isxdigit(line[0])) {
|
if (CheckStringIsHEXValue(line))
|
||||||
PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t key = strtoull(line, NULL, 16);
|
uint64_t key = strtoull(line, NULL, 16);
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ typedef enum {
|
||||||
jsfLegic,
|
jsfLegic,
|
||||||
jsfT55x7,
|
jsfT55x7,
|
||||||
jsfT5555,
|
jsfT5555,
|
||||||
|
jsfMfPlusKeys,
|
||||||
} JSONFileType;
|
} JSONFileType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -175,13 +176,32 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_
|
||||||
*
|
*
|
||||||
* @param preferredName
|
* @param preferredName
|
||||||
* @param data The data array to store the loaded bytes from file
|
* @param data The data array to store the loaded bytes from file
|
||||||
* @param maxdatalen maximum size of data array in bytes
|
* @param datalen the number of bytes loaded from file. may be NULL
|
||||||
* @param datalen the number of bytes loaded from file
|
|
||||||
* @param keylen the number of bytes a key per row is
|
* @param keylen the number of bytes a key per row is
|
||||||
|
* @param keycnt key count that lays in data. may be NULL
|
||||||
* @return 0 for ok, 1 for failz
|
* @return 0 for ok, 1 for failz
|
||||||
*/
|
*/
|
||||||
int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt);
|
int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name.
|
||||||
|
* E.g. mfc_default_keys.dic
|
||||||
|
* can be executed several times for big dictionaries and checks length of buffer
|
||||||
|
*
|
||||||
|
* @param preferredName
|
||||||
|
* @param data The data array to store the loaded bytes from file
|
||||||
|
* @param maxdatalen maximum size of data array in bytes
|
||||||
|
* @param datalen the number of bytes loaded from file. may be NULL
|
||||||
|
* @param keylen the number of bytes a key per row is
|
||||||
|
* @param keycnt key count that lays in data. may be NULL
|
||||||
|
* @param startFilePosition start position in dictionary file. used for big dictionaries.
|
||||||
|
* @param endFilePosition in case we have keys in file and maxdatalen reached it returns current key position in file. may be NULL
|
||||||
|
* @param verbose print messages if true
|
||||||
|
* @return 0 for ok, 1 for failz
|
||||||
|
*/
|
||||||
|
int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt,
|
||||||
|
size_t startFilePosition, size_t *endFilePosition, bool verbose);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name.
|
* @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name.
|
||||||
* E.g. mfc_default_keys.dic
|
* E.g. mfc_default_keys.dic
|
||||||
|
|
|
@ -26,10 +26,10 @@ example =
|
||||||
|
|
||||||
-- This will print the stored Mifare dictionary keys
|
-- This will print the stored Mifare dictionary keys
|
||||||
script run read_pwd_mem -m
|
script run read_pwd_mem -m
|
||||||
|
|
||||||
-- This will print the stored t55xx dictionary passwords
|
-- This will print the stored t55xx dictionary passwords
|
||||||
script run read_pwd_mem -t
|
script run read_pwd_mem -t
|
||||||
|
|
||||||
-- This will print the stored iClass dictionary keys
|
-- This will print the stored iClass dictionary keys
|
||||||
script run read_pwd_mem -i
|
script run read_pwd_mem -i
|
||||||
]]
|
]]
|
||||||
|
|
|
@ -16,7 +16,7 @@ example =
|
||||||
|
|
||||||
-- This will read the other.log file in SPIFFS and print the stored passwords
|
-- This will read the other.log file in SPIFFS and print the stored passwords
|
||||||
script run read_pwd_mem_spiffs -f other.log
|
script run read_pwd_mem_spiffs -f other.log
|
||||||
|
|
||||||
-- This will delete the hf_bog.log file from SPIFFS
|
-- This will delete the hf_bog.log file from SPIFFS
|
||||||
script run read_pwd_mem_spiffs -r
|
script run read_pwd_mem_spiffs -r
|
||||||
]]
|
]]
|
||||||
|
@ -68,7 +68,7 @@ local function main(args)
|
||||||
|
|
||||||
-- offset
|
-- offset
|
||||||
if o == 'f' then filename = a end
|
if o == 'f' then filename = a end
|
||||||
|
|
||||||
-- remove
|
-- remove
|
||||||
if o == 'r' then removeflag = true end
|
if o == 'r' then removeflag = true end
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ local function main(args)
|
||||||
core.console("mem spiffs remove " ..filename)
|
core.console("mem spiffs remove " ..filename)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
data, length, err = core.GetFromFlashMemSpiffs(filename)
|
data, length, err = core.GetFromFlashMemSpiffs(filename)
|
||||||
if data == nil then return oops('Problem while reading file from SPIFFS') end
|
if data == nil then return oops('Problem while reading file from SPIFFS') end
|
||||||
|
|
||||||
|
|
|
@ -168,21 +168,24 @@ int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t
|
||||||
return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen);
|
return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) {
|
int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) {
|
||||||
uint8_t data[257] = {0};
|
uint8_t data[257] = {0};
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
|
|
||||||
uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00};
|
uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00};
|
||||||
uint8_t RndB[17] = {0};
|
uint8_t RndB[17] = {0};
|
||||||
|
|
||||||
|
if (silentMode)
|
||||||
|
verbose = false;
|
||||||
|
|
||||||
if (session)
|
if (session)
|
||||||
session->Authenticated = false;
|
session->Authenticated = false;
|
||||||
|
|
||||||
uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00};
|
uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00};
|
||||||
int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen);
|
int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen, silentMode);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Exchande raw error: %d", res);
|
if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res);
|
||||||
DropField();
|
if (dropFieldIfError) DropField();
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,20 +193,20 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF
|
||||||
PrintAndLogEx(INFO, "<phase1: %s", sprint_hex(data, datalen));
|
PrintAndLogEx(INFO, "<phase1: %s", sprint_hex(data, datalen));
|
||||||
|
|
||||||
if (datalen < 1) {
|
if (datalen < 1) {
|
||||||
PrintAndLogEx(ERR, "Card response wrong length: %d", datalen);
|
if (!silentMode) PrintAndLogEx(ERR, "Card response wrong length: %d", datalen);
|
||||||
DropField();
|
if (dropFieldIfError) DropField();
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[0] != 0x90) {
|
if (data[0] != 0x90) {
|
||||||
PrintAndLogEx(ERR, "Card response error: %02x", data[2]);
|
if (!silentMode) PrintAndLogEx(ERR, "Card response error: %02x", data[2]);
|
||||||
DropField();
|
if (dropFieldIfError) DropField();
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datalen != 19) { // code 1b + 16b + crc 2b
|
if (datalen != 19) { // code 1b + 16b + crc 2b
|
||||||
PrintAndLogEx(ERR, "Card response must be 19 bytes long instead of: %d", datalen);
|
if (!silentMode) PrintAndLogEx(ERR, "Card response must be 19 bytes long instead of: %d", datalen);
|
||||||
DropField();
|
if (dropFieldIfError) DropField();
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,10 +226,10 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, ">phase2: %s", sprint_hex(cmd2, 33));
|
PrintAndLogEx(INFO, ">phase2: %s", sprint_hex(cmd2, 33));
|
||||||
|
|
||||||
res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen);
|
res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen, silentMode);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Exchande raw error: %d", res);
|
if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res);
|
||||||
DropField();
|
if (dropFieldIfError) DropField();
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,12 +244,12 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(&raw[4], &RndA[1], 16)) {
|
if (memcmp(&raw[4], &RndA[1], 16)) {
|
||||||
PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd not equal");
|
if (!silentMode) PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd is not equal");
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16));
|
PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16));
|
||||||
PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16));
|
PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16));
|
||||||
}
|
}
|
||||||
DropField();
|
if (dropFieldIfError) DropField();
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +314,7 @@ static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateFi
|
||||||
if (VerboseMode)
|
if (VerboseMode)
|
||||||
PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
|
PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
|
||||||
|
|
||||||
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false);
|
||||||
|
|
||||||
if (VerboseMode)
|
if (VerboseMode)
|
||||||
PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
|
PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
|
||||||
|
@ -380,7 +383,7 @@ int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data
|
||||||
PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum);
|
PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum);
|
||||||
|
|
||||||
mf4Session session;
|
mf4Session session;
|
||||||
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
|
int res = MifareAuth4(&session, keyn, key, true, true, true, verbose, false);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res);
|
PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res);
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -45,7 +45,7 @@ void mfpSetVerboseMode(bool verbose);
|
||||||
const char *mfpGetErrorDescription(uint8_t errorCode);
|
const char *mfpGetErrorDescription(uint8_t errorCode);
|
||||||
|
|
||||||
int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
|
int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
|
||||||
int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose);
|
int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode);
|
||||||
|
|
||||||
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||||
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||||
|
|
39
client/mifare/mifaredefault.c
Normal file
39
client/mifare/mifaredefault.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2017 Merlok
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Mifare default constants
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "mifaredefault.h"
|
||||||
|
#include "commonutil.h" // ARRAYLEN
|
||||||
|
|
||||||
|
const char *g_mifare_plus_default_keys[] = {
|
||||||
|
"ffffffffffffffffffffffffffffffff", // default key
|
||||||
|
"00000000000000000000000000000000",
|
||||||
|
"a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7", // MAD key
|
||||||
|
"b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7",
|
||||||
|
"d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7", // NDEF key
|
||||||
|
"11111111111111111111111111111111",
|
||||||
|
"22222222222222222222222222222222",
|
||||||
|
"33333333333333333333333333333333",
|
||||||
|
"44444444444444444444444444444444",
|
||||||
|
"55555555555555555555555555555555",
|
||||||
|
"66666666666666666666666666666666",
|
||||||
|
"77777777777777777777777777777777",
|
||||||
|
"88888888888888888888888888888888",
|
||||||
|
"99999999999999999999999999999999",
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||||
|
"cccccccccccccccccccccccccccccccc",
|
||||||
|
"dddddddddddddddddddddddddddddddd",
|
||||||
|
"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
||||||
|
"000102030405060708090a0b0c0d0e0f",
|
||||||
|
"0102030405060708090a0b0c0d0e0f10",
|
||||||
|
"00010203040506070809101112131415",
|
||||||
|
"01020304050607080910111213141516"
|
||||||
|
};
|
||||||
|
size_t g_mifare_plus_default_keys_len = ARRAYLEN(g_mifare_plus_default_keys);
|
|
@ -44,4 +44,7 @@ static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7};
|
||||||
static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7};
|
static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7};
|
||||||
static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7};
|
static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7};
|
||||||
|
|
||||||
|
extern const char *g_mifare_plus_default_keys[];
|
||||||
|
extern size_t g_mifare_plus_default_keys_len;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "mfkey.h"
|
#include "mfkey.h"
|
||||||
#include "util_posix.h" // msclock
|
#include "util_posix.h" // msclock
|
||||||
|
|
||||||
|
|
||||||
int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||||
uint32_t uid = 0;
|
uint32_t uid = 0;
|
||||||
uint32_t nt = 0, nr = 0, ar = 0;
|
uint32_t nt = 0, nr = 0, ar = 0;
|
||||||
|
@ -361,7 +360,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_MIFARE_NESTED, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_MIFARE_NESTED, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_NESTED, &resp, 1500)) return PM3_ETIMEOUT;
|
if (!WaitForResponseTimeout(CMD_HF_MIFARE_NESTED, &resp, 2000)) {
|
||||||
|
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
if (resp.status != PM3_SUCCESS)
|
if (resp.status != PM3_SUCCESS)
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
@ -615,6 +617,50 @@ int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_
|
||||||
return mfCSetBlock(0, block0, oldUID, params);
|
return mfCSetBlock(0, block0, oldUID, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak) {
|
||||||
|
uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF};
|
||||||
|
uint8_t blockD[16] = {0x00};
|
||||||
|
uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
uint8_t params = MAGIC_SINGLE;
|
||||||
|
|
||||||
|
if (uid != NULL) {
|
||||||
|
memcpy(block0, uid, 4);
|
||||||
|
block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3];
|
||||||
|
}
|
||||||
|
if (sak != NULL)
|
||||||
|
block0[5] = sak[0];
|
||||||
|
|
||||||
|
if (atqa != NULL) {
|
||||||
|
block0[6] = atqa[1];
|
||||||
|
block0[7] = atqa[0];
|
||||||
|
}
|
||||||
|
int res;
|
||||||
|
for (int blockNo = 0; blockNo < 4 * 16; blockNo++) {
|
||||||
|
for (int retry = 0; retry < 3; retry++) {
|
||||||
|
if (blockNo == 0) {
|
||||||
|
res = mfCSetBlock(blockNo, block0, NULL, params);
|
||||||
|
} else {
|
||||||
|
if (mfIsSectorTrailer(blockNo))
|
||||||
|
res = mfCSetBlock(blockNo, blockK, NULL, params);
|
||||||
|
else
|
||||||
|
res = mfCSetBlock(blockNo, blockD, NULL, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == PM3_SUCCESS)
|
||||||
|
break;
|
||||||
|
PrintAndLogEx(WARNING, "Retry block[%d]...", blockNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
PrintAndLogEx(ERR, "Error setting block[%d]: %d", blockNo, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) {
|
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) {
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
|
|
|
@ -73,6 +73,7 @@ int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||||
int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
||||||
|
|
||||||
int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard);
|
int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard);
|
||||||
|
int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak);
|
||||||
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
|
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
|
||||||
int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
||||||
|
|
||||||
|
|
|
@ -33,26 +33,25 @@ static void showBanner(void) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "\n");
|
PrintAndLogEx(NORMAL, "\n");
|
||||||
#if defined(__linux__) || (__APPLE__) || (_WIN32)
|
#if defined(__linux__) || (__APPLE__) || (_WIN32)
|
||||||
PrintAndLogEx(NORMAL, _BLUE_("██████╗ ███╗ ███╗ ████╗ ") " ...iceman fork");
|
PrintAndLogEx(NORMAL, " " _BLUE_("██████╗ ███╗ ███╗ ████╗ "));
|
||||||
PrintAndLogEx(NORMAL, _BLUE_("██╔══██╗████╗ ████║ ══█║") " ...dedicated to " _BLUE_("RDV40"));
|
PrintAndLogEx(NORMAL, " " _BLUE_("██╔══██╗████╗ ████║ ══█║"));
|
||||||
PrintAndLogEx(NORMAL, _BLUE_("██████╔╝██╔████╔██║ ████╔╝"));
|
PrintAndLogEx(NORMAL, " " _BLUE_("██████╔╝██╔████╔██║ ████╔╝"));
|
||||||
PrintAndLogEx(NORMAL, _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " iceman@icesql.net");
|
PrintAndLogEx(NORMAL, " " _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " iceman@icesql.net");
|
||||||
PrintAndLogEx(NORMAL, _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/");
|
PrintAndLogEx(NORMAL, " " _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/");
|
||||||
PrintAndLogEx(NORMAL, _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0");
|
PrintAndLogEx(NORMAL, " " _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0");
|
||||||
#else
|
#else
|
||||||
PrintAndLogEx(NORMAL, "======. ===. ===. ====. ...iceman fork");
|
PrintAndLogEx(NORMAL, " ======. ===. ===. ====.");
|
||||||
PrintAndLogEx(NORMAL, "==...==.====. ====. ..=. ...dedicated to RDV40");
|
PrintAndLogEx(NORMAL, " ==...==.====. ====. ..=.");
|
||||||
PrintAndLogEx(NORMAL, "======..==.====.==. ====..");
|
PrintAndLogEx(NORMAL, " ======..==.====.==. ====..");
|
||||||
PrintAndLogEx(NORMAL, "==..... ==..==..==. ..=. iceman@icesql.net");
|
PrintAndLogEx(NORMAL, " ==..... ==..==..==. ..=. iceman@icesql.net");
|
||||||
PrintAndLogEx(NORMAL, "==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/");
|
PrintAndLogEx(NORMAL, " ==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/");
|
||||||
PrintAndLogEx(NORMAL, "... ... ... ..... pre-release v4.0");
|
PrintAndLogEx(NORMAL, " ... ... ... ..... pre-release v4.0");
|
||||||
#endif
|
#endif
|
||||||
PrintAndLogEx(NORMAL, "\nSupport iceman on patreon - https://www.patreon.com/iceman1001/");
|
// PrintAndLogEx(NORMAL, "\nSupport iceman on patreon - https://www.patreon.com/iceman1001/");
|
||||||
PrintAndLogEx(NORMAL, " on paypal - https://www.paypal.me/iceman1001");
|
// PrintAndLogEx(NORMAL, " on paypal - https://www.paypal.me/iceman1001");
|
||||||
// printf("\nMonero: 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP");
|
// printf("\nMonero: 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP");
|
||||||
PrintAndLogEx(NORMAL, "\n");
|
PrintAndLogEx(NORMAL, "");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG;
|
g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,7 +806,7 @@ int main(int argc, char *argv[]) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
if (!session.pm3_present)
|
if (!session.pm3_present)
|
||||||
PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Check \"%s -h\" if it's not what you want.\n", exec_name);
|
PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Check " _YELLOW_("\"%s -h\"") " if it's not what you want.\n", exec_name);
|
||||||
|
|
||||||
#ifdef HAVE_GUI
|
#ifdef HAVE_GUI
|
||||||
|
|
||||||
|
|
|
@ -394,6 +394,46 @@ void print_blocks(uint32_t *data, size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen) {
|
||||||
|
char buf[4] = {0};
|
||||||
|
int indx = 0;
|
||||||
|
int bytesValueLen = 0;
|
||||||
|
while (hexValue[indx]) {
|
||||||
|
if (hexValue[indx] == '\t' || hexValue[indx] == ' ') {
|
||||||
|
indx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isxdigit(hexValue[indx])) {
|
||||||
|
buf[strlen(buf)] = hexValue[indx];
|
||||||
|
} else {
|
||||||
|
// if we have symbols other than spaces and hex
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxBytesValueLen && bytesValueLen >= maxBytesValueLen) {
|
||||||
|
// if we dont have space in buffer and have symbols to translate
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(buf) >= 2) {
|
||||||
|
uint32_t temp = 0;
|
||||||
|
sscanf(buf, "%x", &temp);
|
||||||
|
bytesValue[bytesValueLen] = (uint8_t)(temp & 0xff);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
bytesValueLen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
indx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(buf) > 0)
|
||||||
|
//error when not completed hex bytes
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
return bytesValueLen;
|
||||||
|
}
|
||||||
|
|
||||||
// takes a number (uint64_t) and creates a binarray in dest.
|
// takes a number (uint64_t) and creates a binarray in dest.
|
||||||
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) {
|
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) {
|
||||||
while (len--) {
|
while (len--) {
|
||||||
|
|
|
@ -55,6 +55,7 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st
|
||||||
|
|
||||||
void print_blocks(uint32_t *data, size_t len);
|
void print_blocks(uint32_t *data, size_t len);
|
||||||
|
|
||||||
|
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen);
|
||||||
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
|
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
|
||||||
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
|
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
|
||||||
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
|
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
|
||||||
|
|
|
@ -63,6 +63,9 @@ GND | 6
|
||||||
## Third party notes on using a BusPirate
|
## Third party notes on using a BusPirate
|
||||||
|
|
||||||
* https://github.com/Proxmark/proxmark3/wiki/Debricking-Proxmark3-with-buspirate
|
* https://github.com/Proxmark/proxmark3/wiki/Debricking-Proxmark3-with-buspirate
|
||||||
|
* https://b4cktr4ck2.github.io/De-Brickify-Pm3-RDV2/
|
||||||
|
* https://scund00r.com/all/rfid/2018/05/18/debrick-proxmark.html
|
||||||
|
* https://joanbono.github.io/PoC/Flashing_Proxmark3.html
|
||||||
|
|
||||||
## Third party notes on using a J-Link
|
## Third party notes on using a J-Link
|
||||||
|
|
||||||
|
@ -72,8 +75,6 @@ GND | 6
|
||||||
|
|
||||||
* http://www.lucasoldi.com/2017/01/17/unbrick-proxmark3-with-a-raspberry-pi-and-openocd/
|
* http://www.lucasoldi.com/2017/01/17/unbrick-proxmark3-with-a-raspberry-pi-and-openocd/
|
||||||
|
|
||||||
# Windows
|
|
||||||
|
|
||||||
## Third party notes on using a J-Link on Windows
|
## Third party notes on using a J-Link on Windows
|
||||||
|
|
||||||
* https://github.com/Proxmark/proxmark3/wiki/De-Bricking-Segger
|
* https://github.com/Proxmark/proxmark3/wiki/De-Bricking-Segger
|
||||||
|
|
|
@ -590,6 +590,8 @@ typedef struct {
|
||||||
#define PM3_EWRONGANSVER -16
|
#define PM3_EWRONGANSVER -16
|
||||||
// Memory out-of-bounds error client/pm3: error when a read/write is outside the expected array
|
// Memory out-of-bounds error client/pm3: error when a read/write is outside the expected array
|
||||||
#define PM3_EOUTOFBOUND -17
|
#define PM3_EOUTOFBOUND -17
|
||||||
|
// exchange with card error client/pm3: error when cant get answer from card or got an incorrect answer
|
||||||
|
#define PM3_ECARDEXCHANGE -18
|
||||||
// No data pm3: no data available, no host frame available (not really an error)
|
// No data pm3: no data available, no host frame available (not really an error)
|
||||||
#define PM3_ENODATA -98
|
#define PM3_ENODATA -98
|
||||||
// Quit program client: reserved, order to quit the program
|
// Quit program client: reserved, order to quit the program
|
||||||
|
|
150
tools/pm3_mf7b_wipe.py
Normal file
150
tools/pm3_mf7b_wipe.py
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
#! /usr/bin/env python3.6
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# VULNERS OPENSOURCE
|
||||||
|
# __________________
|
||||||
|
#
|
||||||
|
# Vulners Project [https://vulners.com]
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Author: Kir [isox@vulners.com]
|
||||||
|
# Credits: Dennis Goh [dennis@rfidresearchgroup.com]
|
||||||
|
#
|
||||||
|
# This helper script is made for wiping S50 7byte UID cards with Gen2 magic commands from restored state to blank one.
|
||||||
|
#
|
||||||
|
# Scenario:
|
||||||
|
# You want to clone 7byte Mifare 1k card using RfidResearchGroup Proxmark3 RDV4.0
|
||||||
|
#
|
||||||
|
# Step 1: Dumping original card and making a Mifare 7byte UID clone using S50 7byte UID
|
||||||
|
#
|
||||||
|
# Place original card to the reader.
|
||||||
|
# Dump data and recover keys
|
||||||
|
#
|
||||||
|
# hf mf autopwn
|
||||||
|
#
|
||||||
|
# You will get data, EML and key file. Backup this file, you will need them to wipe the card back to blank state.
|
||||||
|
# Place blank S50 card to the reader.
|
||||||
|
#
|
||||||
|
# Get first line from EML file (block0) and write it down using command
|
||||||
|
#
|
||||||
|
# Place it here
|
||||||
|
# |
|
||||||
|
# |
|
||||||
|
# v
|
||||||
|
# hf mf wrbl 0 B FFFFFFFFFFFF 046E46AAA53480084400120111003113
|
||||||
|
#
|
||||||
|
# Now restore all the data using built-in restore command
|
||||||
|
#
|
||||||
|
# hf mf restore
|
||||||
|
#
|
||||||
|
# Step 2: Recovering S50 7byte UID card to the blank state
|
||||||
|
#
|
||||||
|
# Find current card data files from Step 1 in your backup or if you lost them create them again using 'hf mf autopwn' command.
|
||||||
|
# Place them in current working directory.
|
||||||
|
#
|
||||||
|
# Read hf-mf-CARD_UID-data.eml file and copy it content with CTRL-C.
|
||||||
|
# Place it to the eml variable in this script.
|
||||||
|
#
|
||||||
|
# Check execution command and check device and command name: 'proxmark3 -c "%s" /dev/tty.usbmodemiceman1'
|
||||||
|
#
|
||||||
|
# Run script and review key blocks returning to default FFFFFFFFFFFF state.
|
||||||
|
# Be patient! It is executing aprox 3 minutes.
|
||||||
|
# Success one result looks like:
|
||||||
|
#
|
||||||
|
# Block 0: Success: isOk:01
|
||||||
|
# Block 3: Success: isOk:01
|
||||||
|
# Block 7: Success: isOk:01
|
||||||
|
# Block 11: Success: isOk:01
|
||||||
|
# Block 15: Success: isOk:01
|
||||||
|
# Block 19: Success: isOk:01
|
||||||
|
# Block 23: Success: isOk:01
|
||||||
|
# Block 27: Success: isOk:01
|
||||||
|
# Block 31: Success: isOk:01
|
||||||
|
# Block 35: Success: isOk:01
|
||||||
|
# Block 39: Success: isOk:01
|
||||||
|
# Block 43: Success: isOk:01
|
||||||
|
# Block 47: Success: isOk:01
|
||||||
|
# Block 51: Success: isOk:01
|
||||||
|
# Block 55: Success: isOk:01
|
||||||
|
# Block 59: Success: isOk:01
|
||||||
|
# Block 63: Success: isOk:01
|
||||||
|
#
|
||||||
|
# Thats it! Your S50 7byte UID card is wiped back. Now you can return back to Step 1 of this manual.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# EML data var te get keys of
|
||||||
|
EML_FILE_DATA = """PLACE RAW hf-mf-CARD_UID-data.eml FILE CONTENT OF CURRENTLY LOADED CARD HERE"""
|
||||||
|
# Change your device name here if it differs from the default Proxmark3 RDV4.0
|
||||||
|
PROXMARK_BIN_EXEC_STRING = 'proxmark3 -c "%s" /dev/tty.usbmodemiceman1'
|
||||||
|
# Constants
|
||||||
|
DEFAULT_ACCESS_BLOCK = "FFFFFFFFFFFFFF078000FFFFFFFFFFFF"
|
||||||
|
F12_KEY = "FFFFFFFFFFFF"
|
||||||
|
|
||||||
|
def exec_proxmark_cmd(command, retry = 2, input=""):
|
||||||
|
exec_ok = False
|
||||||
|
retry_c = 0
|
||||||
|
while not exec_ok and retry_c < retry:
|
||||||
|
sh_command = PROXMARK_BIN_EXEC_STRING % command
|
||||||
|
rst = subprocess.run(sh_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
|
||||||
|
|
||||||
|
proxmark_reply = rst.stdout.decode("utf-8")
|
||||||
|
proxmark_status = proxmark_reply.splitlines()[-1:][0].strip()
|
||||||
|
if proxmark_status == "isOk:01":
|
||||||
|
return True, "Success: " + proxmark_status
|
||||||
|
retry_c += 1
|
||||||
|
return False, "Error: %s , status %s" % (proxmark_reply.splitlines()[-2:][0], proxmark_status)
|
||||||
|
|
||||||
|
|
||||||
|
def chunk(iterable,n):
|
||||||
|
"""assumes n is an integer>0
|
||||||
|
"""
|
||||||
|
iterable=iter(iterable)
|
||||||
|
while True:
|
||||||
|
result=[]
|
||||||
|
for i in range(n):
|
||||||
|
try:
|
||||||
|
a=next(iterable)
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
result.append(a)
|
||||||
|
if result:
|
||||||
|
yield result
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
sector_array = [sector for sector in chunk(EML_FILE_DATA.splitlines(), 4)]
|
||||||
|
block = 0
|
||||||
|
block_success = {}
|
||||||
|
|
||||||
|
for sector in sector_array:
|
||||||
|
key_A = sector[3][:12]
|
||||||
|
key_B = sector[3][-12:]
|
||||||
|
for _block in range(0,4):
|
||||||
|
if sector_array.index(sector) == 0 and block == 0:
|
||||||
|
write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s B %s %s" % (block, key_B, sector[0]))
|
||||||
|
if not write_status:
|
||||||
|
write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, key_A, sector[0]))
|
||||||
|
if not write_status:
|
||||||
|
write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, F12_KEY, sector[0]))
|
||||||
|
block_success[block] = verbose
|
||||||
|
|
||||||
|
elif _block == 3:
|
||||||
|
write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s B %s %s" % (block, key_B, DEFAULT_ACCESS_BLOCK))
|
||||||
|
if not write_status:
|
||||||
|
write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, key_A, DEFAULT_ACCESS_BLOCK))
|
||||||
|
if not write_status:
|
||||||
|
write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, F12_KEY, DEFAULT_ACCESS_BLOCK))
|
||||||
|
block_success[block] = verbose
|
||||||
|
|
||||||
|
_block += 1
|
||||||
|
block += 1
|
||||||
|
|
||||||
|
for block in block_success:
|
||||||
|
print("Block %s: %s" % (block ,block_success[block]))
|
Loading…
Add table
Add a link
Reference in a new issue