mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 13:00:42 -07:00
st -> st25ta
This commit is contained in:
parent
4c44138557
commit
4b00db8e48
11 changed files with 794 additions and 755 deletions
|
@ -253,6 +253,7 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdhfmfu.c
|
${PM3_ROOT}/client/src/cmdhfmfu.c
|
||||||
${PM3_ROOT}/client/src/cmdhfseos.c
|
${PM3_ROOT}/client/src/cmdhfseos.c
|
||||||
${PM3_ROOT}/client/src/cmdhfst.c
|
${PM3_ROOT}/client/src/cmdhfst.c
|
||||||
|
${PM3_ROOT}/client/src/cmdhfst25ta.c
|
||||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||||
|
|
|
@ -485,6 +485,7 @@ SRCS = aiddesfire.c \
|
||||||
cmdhfmfp.c \
|
cmdhfmfp.c \
|
||||||
cmdhfseos.c \
|
cmdhfseos.c \
|
||||||
cmdhfst.c \
|
cmdhfst.c \
|
||||||
|
cmdhfst25ta.c \
|
||||||
cmdhfthinfilm.c \
|
cmdhfthinfilm.c \
|
||||||
cmdhftopaz.c \
|
cmdhftopaz.c \
|
||||||
cmdhfwaveshare.c \
|
cmdhfwaveshare.c \
|
||||||
|
|
|
@ -120,6 +120,7 @@ add_library(pm3rrg_rdv4 SHARED
|
||||||
${PM3_ROOT}/client/src/cmdhfmfp.c
|
${PM3_ROOT}/client/src/cmdhfmfp.c
|
||||||
${PM3_ROOT}/client/src/cmdhfmfu.c
|
${PM3_ROOT}/client/src/cmdhfmfu.c
|
||||||
${PM3_ROOT}/client/src/cmdhfst.c
|
${PM3_ROOT}/client/src/cmdhfst.c
|
||||||
|
${PM3_ROOT}/client/src/cmdhfst25ta.c
|
||||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||||
|
|
|
@ -252,6 +252,7 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdhfmfp.c
|
${PM3_ROOT}/client/src/cmdhfmfp.c
|
||||||
${PM3_ROOT}/client/src/cmdhfmfu.c
|
${PM3_ROOT}/client/src/cmdhfmfu.c
|
||||||
${PM3_ROOT}/client/src/cmdhfst.c
|
${PM3_ROOT}/client/src/cmdhfst.c
|
||||||
|
${PM3_ROOT}/client/src/cmdhfst25ta.c
|
||||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#include "cmdhflto.h" // LTO-CM
|
#include "cmdhflto.h" // LTO-CM
|
||||||
#include "cmdhfcryptorf.h" // CryptoRF
|
#include "cmdhfcryptorf.h" // CryptoRF
|
||||||
#include "cmdhfseos.h" // SEOS
|
#include "cmdhfseos.h" // SEOS
|
||||||
#include "cmdhfst.h" // ST rothult
|
#include "cmdhfst25ta.h" // ST25TA
|
||||||
#include "cmdhfwaveshare.h" // Waveshare
|
#include "cmdhfwaveshare.h" // Waveshare
|
||||||
#include "cmdtrace.h" // trace list
|
#include "cmdtrace.h" // trace list
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
@ -412,7 +412,7 @@ static command_t CommandTable[] = {
|
||||||
{"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"},
|
{"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"},
|
||||||
{"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"},
|
{"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"},
|
||||||
{"seos", CmdHFSeos, AlwaysAvailable, "{ SEOS RFIDs... }"},
|
{"seos", CmdHFSeos, AlwaysAvailable, "{ SEOS RFIDs... }"},
|
||||||
{"st", CmdHFST, AlwaysAvailable, "{ ST Rothult RFIDs... }"},
|
{"st25ta", CmdHFST25TA, AlwaysAvailable, "{ ST25TA RFIDs... }"},
|
||||||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||||
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
||||||
|
|
|
@ -9,24 +9,13 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "cmdhfst.h"
|
#include "cmdhfst.h"
|
||||||
#include <ctype.h>
|
#include <string.h>
|
||||||
#include "fileutils.h"
|
#include <stdio.h>
|
||||||
#include "cmdparser.h" // command_t
|
|
||||||
#include "comms.h" // clearCommandBuffer
|
|
||||||
#include "cmdtrace.h"
|
|
||||||
#include "cliparser.h"
|
|
||||||
#include "crc16.h"
|
|
||||||
#include "cmdhf14a.h"
|
|
||||||
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
|
||||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
|
||||||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
|
||||||
|
|
||||||
#define TIMEOUT 2000
|
#define TIMEOUT 2000
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
|
||||||
|
|
||||||
// get ST Microelectronics chip model (from UID)
|
// get ST Microelectronics chip model (from UID)
|
||||||
static char *get_st_chip_model(uint8_t pc) {
|
char *get_st_chip_model(uint8_t pc) {
|
||||||
static char model[40];
|
static char model[40];
|
||||||
char *s = model;
|
char *s = model;
|
||||||
memset(model, 0, sizeof(model));
|
memset(model, 0, sizeof(model));
|
||||||
|
@ -78,7 +67,7 @@ static char *get_st_chip_model(uint8_t pc) {
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
// print UID info from SRx chips (ST Microelectronics)
|
// print UID info from SRx chips (ST Microelectronics)
|
||||||
static void print_st_general_info(uint8_t *data, uint8_t len) {
|
void print_st_general_info(uint8_t *data, uint8_t len) {
|
||||||
//uid = first 8 bytes in data
|
//uid = first 8 bytes in data
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(SwapEndian64(data, 8, 8), len));
|
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(SwapEndian64(data, 8, 8), len));
|
||||||
|
@ -87,728 +76,3 @@ static void print_st_general_info(uint8_t *data, uint8_t len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
static void print_st_cc_info(uint8_t *d, uint8_t n) {
|
|
||||||
if (n < 0x0F) {
|
|
||||||
PrintAndLogEx(WARNING, "Not enought bytes read from system file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(SUCCESS, "------------ " _CYAN_("Capability Container file") " ------------");
|
|
||||||
PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%02X") ")", d[1], d[1]);
|
|
||||||
PrintAndLogEx(SUCCESS, " version %s (" _GREEN_("0x%02X") ")", (d[2] == 0x20) ? "v2.0" : "v1.0", d[2]);
|
|
||||||
|
|
||||||
uint16_t maxr = (d[3] << 8 | d[4]);
|
|
||||||
PrintAndLogEx(SUCCESS, " max bytes read %u bytes ( 0x%04X )", maxr, maxr);
|
|
||||||
uint16_t maxw = (d[5] << 8 | d[6]);
|
|
||||||
PrintAndLogEx(SUCCESS, " max bytes write %u bytes ( 0x%04X )", maxw, maxw);
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(SUCCESS, " NDEF file control TLV {");
|
|
||||||
PrintAndLogEx(SUCCESS, " (t) type of file ( %02X )", d[7]);
|
|
||||||
PrintAndLogEx(SUCCESS, " (v) ( %02X )", d[8]);
|
|
||||||
PrintAndLogEx(SUCCESS, " file id ( %02X%02X )", d[9], d[10]);
|
|
||||||
|
|
||||||
uint16_t maxndef = (d[11] << 8 | d[12]);
|
|
||||||
PrintAndLogEx(SUCCESS, " max NDEF filesize %u bytes ( 0x%04X )", maxndef, maxndef);
|
|
||||||
PrintAndLogEx(SUCCESS, " ----- " _CYAN_("access rights") " -------");
|
|
||||||
PrintAndLogEx(SUCCESS, " read ( %02X ) protection: %s", d[13], ((d[13] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled"));
|
|
||||||
PrintAndLogEx(SUCCESS, " write ( %02X ) protection: %s", d[14], ((d[14] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled"));
|
|
||||||
PrintAndLogEx(SUCCESS, " }");
|
|
||||||
PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------");
|
|
||||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
}
|
|
||||||
static void print_st_system_info(uint8_t *d, uint8_t n) {
|
|
||||||
if (n < 0x12) {
|
|
||||||
PrintAndLogEx(WARNING, "Not enought bytes read from system file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------");
|
|
||||||
|
|
||||||
uint16_t len = (d[0] << 8 | d[1]);
|
|
||||||
PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%04X") ")", len, len);
|
|
||||||
|
|
||||||
if (d[2] == 0x80) {
|
|
||||||
PrintAndLogEx(SUCCESS, " ST reserved ( 0x%02X )", d[2]);
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(SUCCESS, " GPO Config ( 0x%02X )", d[2]);
|
|
||||||
PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
|
|
||||||
uint8_t conf = (d[2] & 0x70) >> 4;
|
|
||||||
switch (conf) {
|
|
||||||
case 0:
|
|
||||||
PrintAndLogEx(SUCCESS, "");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
PrintAndLogEx(SUCCESS, "Session opened");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
PrintAndLogEx(SUCCESS, "WIP");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
PrintAndLogEx(SUCCESS, "MIP");
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
PrintAndLogEx(SUCCESS, "Interrupt");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
PrintAndLogEx(SUCCESS, "State Control");
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
PrintAndLogEx(SUCCESS, "RF Busy");
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
PrintAndLogEx(SUCCESS, "Field Detect");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " Event counter config ( 0x%02X )", d[3]);
|
|
||||||
PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[3] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
|
|
||||||
PrintAndLogEx(SUCCESS, " counter ( %s )", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable"));
|
|
||||||
PrintAndLogEx(SUCCESS, " counter increment on ( %s )", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read"));
|
|
||||||
|
|
||||||
uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]);
|
|
||||||
PrintAndLogEx(SUCCESS, " 20bit counter ( 0x%05X )", counter & 0xFFFFF);
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " Product version ( 0x%02X )", d[7]);
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " UID " _GREEN_("%s"), sprint_hex_inrow(d + 8, 7));
|
|
||||||
PrintAndLogEx(SUCCESS, " MFG 0x%02X, " _YELLOW_("%s"), d[8], getTagInfo(d[8]));
|
|
||||||
PrintAndLogEx(SUCCESS, " Product Code 0x%02X, " _YELLOW_("%s"), d[9], get_st_chip_model(d[9]));
|
|
||||||
PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5));
|
|
||||||
|
|
||||||
uint16_t mem = (d[0xF] << 8 | d[0x10]);
|
|
||||||
PrintAndLogEx(SUCCESS, " Memory Size - 1 %u bytes (" _GREEN_("0x%04X") ")", mem, mem);
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " IC Reference code %u ( 0x%02X )", d[0x12], d[0x12]);
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------");
|
|
||||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
|
|
||||||
/*
|
|
||||||
0012
|
|
||||||
80000000001302E2007D0E8DCC
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t get_sw(uint8_t *d, uint8_t n) {
|
|
||||||
if (n < 2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
n -= 2;
|
|
||||||
return d[n] * 0x0100 + d[n + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ST rothult
|
|
||||||
static int infoHFST(void) {
|
|
||||||
|
|
||||||
bool activate_field = true;
|
|
||||||
bool keep_field_on = true;
|
|
||||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
|
||||||
int resplen = 0;
|
|
||||||
|
|
||||||
// --------------- Select NDEF Tag application ----------------
|
|
||||||
uint8_t aSELECT_AID[80];
|
|
||||||
int aSELECT_AID_n = 0;
|
|
||||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
|
||||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resplen < 2) {
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
activate_field = false;
|
|
||||||
keep_field_on = true;
|
|
||||||
// --------------- CC file reading ----------------
|
|
||||||
|
|
||||||
uint8_t aSELECT_FILE_CC[30];
|
|
||||||
int aSELECT_FILE_CC_n = 0;
|
|
||||||
param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n);
|
|
||||||
res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t aREAD_CC[30];
|
|
||||||
int aREAD_CC_n = 0;
|
|
||||||
param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n);
|
|
||||||
res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
// store st cc data for later
|
|
||||||
uint8_t st_cc_data[resplen - 2];
|
|
||||||
memcpy(st_cc_data, response, sizeof(st_cc_data));
|
|
||||||
|
|
||||||
// --------------- System file reading ----------------
|
|
||||||
uint8_t aSELECT_FILE_SYS[30];
|
|
||||||
int aSELECT_FILE_SYS_n = 0;
|
|
||||||
param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n);
|
|
||||||
res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
keep_field_on = false;
|
|
||||||
|
|
||||||
uint8_t aREAD_SYS[30];
|
|
||||||
int aREAD_SYS_n = 0;
|
|
||||||
param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n);
|
|
||||||
res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
print_st_cc_info(st_cc_data, sizeof(st_cc_data));
|
|
||||||
print_st_system_info(response, resplen - 2);
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// menu command to get and print all info known about any known ST25TA tag
|
|
||||||
static int CmdHFSTInfo(const char *Cmd) {
|
|
||||||
CLIParserContext *ctx;
|
|
||||||
CLIParserInit(&ctx, "hf st info",
|
|
||||||
"Get info about ST25TA tag",
|
|
||||||
"hf st info"
|
|
||||||
);
|
|
||||||
|
|
||||||
void *argtable[] = {
|
|
||||||
arg_param_begin,
|
|
||||||
arg_param_end
|
|
||||||
};
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
return infoHFST();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFSTSim(const char *Cmd) {
|
|
||||||
int uidlen = 0;
|
|
||||||
uint8_t uid[7] = {0};
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
|
||||||
CLIParserInit(&ctx, "hf st sim",
|
|
||||||
"Emulating ST25TA512B tag with 7 byte UID",
|
|
||||||
"hf st sim -u 02E2007D0FCA4C\n");
|
|
||||||
|
|
||||||
void *argtable[] = {
|
|
||||||
arg_param_begin,
|
|
||||||
arg_str1("u", "uid", "<hex>", "7 byte UID"),
|
|
||||||
arg_param_end
|
|
||||||
};
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
|
||||||
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
|
|
||||||
if (uidlen != 7) {
|
|
||||||
PrintAndLogEx(ERR, "UID must be 7 hex bytes");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
char param[40];
|
|
||||||
snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen));
|
|
||||||
return CmdHF14ASim(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CmdHFSTNdefRead(const char *Cmd) {
|
|
||||||
int pwdlen = 0;
|
|
||||||
uint8_t pwd[16] = {0};
|
|
||||||
bool with_pwd = false;
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
|
||||||
CLIParserInit(&ctx, "hf st ndefread",
|
|
||||||
"Read NFC Data Exchange Format (NDEF) file on ST25TA",
|
|
||||||
"hf st ndefread -p 82E80053D4CA5C0B656D852CC696C8A1\n");
|
|
||||||
|
|
||||||
void *argtable[] = {
|
|
||||||
arg_param_begin,
|
|
||||||
arg_str0("p", "pwd", "<hex>", "16 byte read password"),
|
|
||||||
arg_param_end
|
|
||||||
};
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
|
||||||
CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
|
|
||||||
if (pwdlen == 0) {
|
|
||||||
with_pwd = false;
|
|
||||||
} else {
|
|
||||||
if (pwdlen != 16) {
|
|
||||||
PrintAndLogEx(ERR, "Password must be 16 hex bytes");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
with_pwd = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool activate_field = true;
|
|
||||||
bool keep_field_on = true;
|
|
||||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
|
||||||
int resplen = 0;
|
|
||||||
|
|
||||||
// --------------- Select NDEF Tag application ----------------
|
|
||||||
uint8_t aSELECT_AID[80];
|
|
||||||
int aSELECT_AID_n = 0;
|
|
||||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
|
||||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resplen < 2) {
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
activate_field = false;
|
|
||||||
keep_field_on = true;
|
|
||||||
|
|
||||||
// --------------- NDEF file reading ----------------
|
|
||||||
uint8_t aSELECT_FILE_NDEF[30];
|
|
||||||
int aSELECT_FILE_NDEF_n = 0;
|
|
||||||
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
|
||||||
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (with_pwd) {
|
|
||||||
// --------------- VERIFY ----------------
|
|
||||||
uint8_t aVERIFY[30];
|
|
||||||
int aVERIFY_n = 0;
|
|
||||||
param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
|
||||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw == 0x6300) {
|
|
||||||
// need to provide 16byte password
|
|
||||||
param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
|
||||||
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
|
||||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
keep_field_on = false;
|
|
||||||
uint8_t aREAD_NDEF[30];
|
|
||||||
int aREAD_NDEF_n = 0;
|
|
||||||
param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
|
|
||||||
res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
NDEFRecordsDecodeAndPrint(response + 2, resplen - 4);
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFSTProtect(const char *Cmd) {
|
|
||||||
|
|
||||||
int pwdlen = 0;
|
|
||||||
uint8_t pwd[16] = {0};
|
|
||||||
int statelen = 3;
|
|
||||||
uint8_t state[3] = {0x26, 0, 0x02};
|
|
||||||
|
|
||||||
bool disable_protection = false;
|
|
||||||
bool enable_protection = false;
|
|
||||||
bool read_protection = false;
|
|
||||||
bool write_protection = false;
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
|
||||||
CLIParserInit(&ctx, "hf st protect",
|
|
||||||
"Change read or write protection for NFC Data Exchange Format (NDEF) file on ST25TA",
|
|
||||||
"hf st protect -p 82E80053D4CA5C0B656D852CC696C8A1 -r -e -> enable read protection\n"
|
|
||||||
"hf st protect -p 82E80053D4CA5C0B656D852CC696C8A1 -w -d -> disable write protection\n");
|
|
||||||
|
|
||||||
void *argtable[] = {
|
|
||||||
arg_param_begin,
|
|
||||||
arg_lit0("e", "enable", "enable protection"),
|
|
||||||
arg_lit0("d", "disable", "disable protection (default)"),
|
|
||||||
arg_lit0("r", "read", "change read protection"),
|
|
||||||
arg_lit0("w", "write", "change write protection (default)"),
|
|
||||||
arg_str1("p", "password", "<hex>", "16 byte write password"),
|
|
||||||
arg_param_end
|
|
||||||
};
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
|
||||||
|
|
||||||
enable_protection = arg_get_lit(ctx, 1);
|
|
||||||
disable_protection = arg_get_lit(ctx, 2);
|
|
||||||
read_protection = arg_get_lit(ctx, 3);
|
|
||||||
write_protection = arg_get_lit(ctx, 4);
|
|
||||||
CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
|
|
||||||
//Validations
|
|
||||||
if (enable_protection && disable_protection) {
|
|
||||||
PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
if (enable_protection) {
|
|
||||||
state[0] = 0x28;
|
|
||||||
}
|
|
||||||
if (disable_protection) {
|
|
||||||
state[0] = 0x26;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_protection && write_protection) {
|
|
||||||
PrintAndLogEx(ERR, "Must specify either read or write protection, not both");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
if (read_protection) {
|
|
||||||
state[2] = 0x01;
|
|
||||||
}
|
|
||||||
if (write_protection) {
|
|
||||||
state[2] = 0x02;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pwdlen != 16) {
|
|
||||||
PrintAndLogEx(ERR, "Missing 16 byte password");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool activate_field = true;
|
|
||||||
bool keep_field_on = true;
|
|
||||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
|
||||||
int resplen = 0;
|
|
||||||
|
|
||||||
// --------------- Select NDEF Tag application ----------------
|
|
||||||
uint8_t aSELECT_AID[80];
|
|
||||||
int aSELECT_AID_n = 0;
|
|
||||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
|
||||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resplen < 2) {
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
activate_field = false;
|
|
||||||
keep_field_on = true;
|
|
||||||
|
|
||||||
// --------------- Select NDEF file ----------------
|
|
||||||
uint8_t aSELECT_FILE_NDEF[30];
|
|
||||||
int aSELECT_FILE_NDEF_n = 0;
|
|
||||||
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
|
||||||
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- VERIFY ----------------
|
|
||||||
uint8_t aVERIFY[30];
|
|
||||||
int aVERIFY_n = 0;
|
|
||||||
// need to provide 16byte password
|
|
||||||
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
|
||||||
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
|
||||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- Change protection ----------------
|
|
||||||
keep_field_on = false;
|
|
||||||
uint8_t aPROTECT[30];
|
|
||||||
int aPROTECT_n = 0;
|
|
||||||
param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n);
|
|
||||||
memcpy(aPROTECT + aPROTECT_n, state, statelen);
|
|
||||||
res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"),
|
|
||||||
((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled"));
|
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFSTPwd(const char *Cmd) {
|
|
||||||
|
|
||||||
int pwdlen = 0;
|
|
||||||
uint8_t pwd[16] = {0};
|
|
||||||
int newpwdlen = 0;
|
|
||||||
uint8_t newpwd[16] = {0};
|
|
||||||
int changePwdlen = 4;
|
|
||||||
uint8_t changePwd[4] = {0x24, 0x00, 0x01, 0x10};
|
|
||||||
bool change_read_password = false;
|
|
||||||
bool change_write_password = false;
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
|
||||||
CLIParserInit(&ctx, "hf st pwd",
|
|
||||||
"Change read or write password for NFC Data Exchange Format (NDEF) file on ST25TA",
|
|
||||||
"hf st pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -r -n 00000000000000000000000000000000 -> change read password\n"
|
|
||||||
"hf st pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -w -n 00000000000000000000000000000000 -> change write password\n");
|
|
||||||
|
|
||||||
void *argtable[] = {
|
|
||||||
arg_param_begin,
|
|
||||||
arg_lit0("r", "read", "change the read password (default)"),
|
|
||||||
arg_lit0("w", "write", "change the write password"),
|
|
||||||
arg_str1("p", "password", "<hex>", "current 16 byte write password"),
|
|
||||||
arg_str1("n", "new", "<hex>", "new 16 byte password"),
|
|
||||||
arg_param_end
|
|
||||||
};
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
|
||||||
|
|
||||||
change_read_password = arg_get_lit(ctx, 1);
|
|
||||||
change_write_password = arg_get_lit(ctx, 2);
|
|
||||||
CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen);
|
|
||||||
CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
|
|
||||||
if (change_read_password && change_write_password) {
|
|
||||||
PrintAndLogEx(ERR, "Must specify either read or write, not both");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
if (change_read_password) {
|
|
||||||
changePwd[2] = 0x01;
|
|
||||||
}
|
|
||||||
if (change_write_password) {
|
|
||||||
changePwd[2] = 0x02;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pwdlen != 16) {
|
|
||||||
PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
if (newpwdlen != 16) {
|
|
||||||
PrintAndLogEx(ERR, "New password must be 16 hex bytes");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool activate_field = true;
|
|
||||||
bool keep_field_on = true;
|
|
||||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
|
||||||
int resplen = 0;
|
|
||||||
|
|
||||||
// --------------- Select NDEF Tag application ----------------
|
|
||||||
uint8_t aSELECT_AID[80];
|
|
||||||
int aSELECT_AID_n = 0;
|
|
||||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
|
||||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resplen < 2) {
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
activate_field = false;
|
|
||||||
keep_field_on = true;
|
|
||||||
|
|
||||||
// --------------- Select NDEF file ----------------
|
|
||||||
uint8_t aSELECT_FILE_NDEF[30];
|
|
||||||
int aSELECT_FILE_NDEF_n = 0;
|
|
||||||
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
|
||||||
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- VERIFY ----------------
|
|
||||||
uint8_t aVERIFY[30];
|
|
||||||
int aVERIFY_n = 0;
|
|
||||||
// need to provide 16byte password
|
|
||||||
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
|
||||||
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
|
||||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- Change password ----------------
|
|
||||||
|
|
||||||
keep_field_on = false;
|
|
||||||
uint8_t aCHG_PWD[30];
|
|
||||||
int aCHG_PWD_n = 0;
|
|
||||||
param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n);
|
|
||||||
memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen);
|
|
||||||
memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen);
|
|
||||||
res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
DropField();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
sw = get_sw(response, resplen);
|
|
||||||
if (sw != 0x9000) {
|
|
||||||
PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"));
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFSTList(const char *Cmd) {
|
|
||||||
return CmdTraceListAlias(Cmd, "hf st", "7816");
|
|
||||||
}
|
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
|
||||||
{"info", CmdHFSTInfo, IfPm3Iso14443a, "Tag information"},
|
|
||||||
{"list", CmdHFSTList, AlwaysAvailable, "List ISO 14443A/7816 history"},
|
|
||||||
{"ndefread", CmdHFSTNdefRead, AlwaysAvailable, "read NDEF file on tag"},
|
|
||||||
{"protect", CmdHFSTProtect, IfPm3Iso14443a, "change protection on tag"},
|
|
||||||
{"pwd", CmdHFSTPwd, IfPm3Iso14443a, "change password on tag"},
|
|
||||||
{"sim", CmdHFSTSim, IfPm3Iso14443a, "Fake ISO 14443A/ST tag"},
|
|
||||||
{NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd) {
|
|
||||||
(void)Cmd; // Cmd is not used so far
|
|
||||||
CmdsHelp(CommandTable);
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CmdHFST(const char *Cmd) {
|
|
||||||
clearCommandBuffer();
|
|
||||||
return CmdsParse(CommandTable, Cmd);
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
int CmdHFST(const char *Cmd);
|
char *get_st_chip_model(uint8_t pc);
|
||||||
int CmdHFSTNdefRead(const char *Cmd);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
753
client/src/cmdhfst25ta.c
Normal file
753
client/src/cmdhfst25ta.c
Normal file
|
@ -0,0 +1,753 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2020 iceman1001
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// High frequency ISO14443A / ST25TA commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "cmdhfst25ta.h"
|
||||||
|
#include "cmdhfst.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "fileutils.h"
|
||||||
|
#include "cmdparser.h" // command_t
|
||||||
|
#include "comms.h" // clearCommandBuffer
|
||||||
|
#include "cmdtrace.h"
|
||||||
|
#include "cliparser.h"
|
||||||
|
#include "crc16.h"
|
||||||
|
#include "cmdhf14a.h"
|
||||||
|
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
||||||
|
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||||
|
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||||
|
|
||||||
|
#define TIMEOUT 2000
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
static void print_st25ta_cc_info(uint8_t *d, uint8_t n) {
|
||||||
|
if (n < 0x0F) {
|
||||||
|
PrintAndLogEx(WARNING, "Not enough bytes read from system file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, "------------ " _CYAN_("Capability Container file") " ------------");
|
||||||
|
PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%02X") ")", d[1], d[1]);
|
||||||
|
PrintAndLogEx(SUCCESS, " version %s (" _GREEN_("0x%02X") ")", (d[2] == 0x20) ? "v2.0" : "v1.0", d[2]);
|
||||||
|
|
||||||
|
uint16_t maxr = (d[3] << 8 | d[4]);
|
||||||
|
PrintAndLogEx(SUCCESS, " max bytes read %u bytes ( 0x%04X )", maxr, maxr);
|
||||||
|
uint16_t maxw = (d[5] << 8 | d[6]);
|
||||||
|
PrintAndLogEx(SUCCESS, " max bytes write %u bytes ( 0x%04X )", maxw, maxw);
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, " NDEF file control TLV {");
|
||||||
|
PrintAndLogEx(SUCCESS, " (t) type of file ( %02X )", d[7]);
|
||||||
|
PrintAndLogEx(SUCCESS, " (v) ( %02X )", d[8]);
|
||||||
|
PrintAndLogEx(SUCCESS, " file id ( %02X%02X )", d[9], d[10]);
|
||||||
|
|
||||||
|
uint16_t maxndef = (d[11] << 8 | d[12]);
|
||||||
|
PrintAndLogEx(SUCCESS, " max NDEF filesize %u bytes ( 0x%04X )", maxndef, maxndef);
|
||||||
|
PrintAndLogEx(SUCCESS, " ----- " _CYAN_("access rights") " -------");
|
||||||
|
PrintAndLogEx(SUCCESS, " read ( %02X ) protection: %s", d[13], ((d[13] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled"));
|
||||||
|
PrintAndLogEx(SUCCESS, " write ( %02X ) protection: %s", d[14], ((d[14] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled"));
|
||||||
|
PrintAndLogEx(SUCCESS, " }");
|
||||||
|
PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------");
|
||||||
|
PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
static void print_st25ta_system_info(uint8_t *d, uint8_t n) {
|
||||||
|
if (n < 0x12) {
|
||||||
|
PrintAndLogEx(WARNING, "Not enough bytes read from system file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------");
|
||||||
|
|
||||||
|
uint16_t len = (d[0] << 8 | d[1]);
|
||||||
|
PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%04X") ")", len, len);
|
||||||
|
|
||||||
|
if (d[2] == 0x80) {
|
||||||
|
PrintAndLogEx(SUCCESS, " ST reserved ( 0x%02X )", d[2]);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(SUCCESS, " GPO Config ( 0x%02X )", d[2]);
|
||||||
|
PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
|
||||||
|
uint8_t conf = (d[2] & 0x70) >> 4;
|
||||||
|
switch (conf) {
|
||||||
|
case 0:
|
||||||
|
PrintAndLogEx(SUCCESS, "");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
PrintAndLogEx(SUCCESS, "Session opened");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
PrintAndLogEx(SUCCESS, "WIP");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
PrintAndLogEx(SUCCESS, "MIP");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
PrintAndLogEx(SUCCESS, "Interrupt");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
PrintAndLogEx(SUCCESS, "State Control");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
PrintAndLogEx(SUCCESS, "RF Busy");
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
PrintAndLogEx(SUCCESS, "Field Detect");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, " Event counter config ( 0x%02X )", d[3]);
|
||||||
|
PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[3] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
|
||||||
|
PrintAndLogEx(SUCCESS, " counter ( %s )", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable"));
|
||||||
|
PrintAndLogEx(SUCCESS, " counter increment on ( %s )", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read"));
|
||||||
|
|
||||||
|
uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]);
|
||||||
|
PrintAndLogEx(SUCCESS, " 20bit counter ( 0x%05X )", counter & 0xFFFFF);
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, " Product version ( 0x%02X )", d[7]);
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, " UID " _GREEN_("%s"), sprint_hex_inrow(d + 8, 7));
|
||||||
|
PrintAndLogEx(SUCCESS, " MFG 0x%02X, " _YELLOW_("%s"), d[8], getTagInfo(d[8]));
|
||||||
|
PrintAndLogEx(SUCCESS, " Product Code 0x%02X, " _YELLOW_("%s"), d[9], get_st_chip_model(d[9]));
|
||||||
|
PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5));
|
||||||
|
|
||||||
|
uint16_t mem = (d[0xF] << 8 | d[0x10]);
|
||||||
|
PrintAndLogEx(SUCCESS, " Memory Size - 1 %u bytes (" _GREEN_("0x%04X") ")", mem, mem);
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, " IC Reference code %u ( 0x%02X )", d[0x12], d[0x12]);
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------");
|
||||||
|
PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
|
/*
|
||||||
|
0012
|
||||||
|
80000000001302E2007D0E8DCC
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t get_sw(uint8_t *d, uint8_t n) {
|
||||||
|
if (n < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
n -= 2;
|
||||||
|
return d[n] * 0x0100 + d[n + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ST25TA
|
||||||
|
static int infoHFST25TA(void) {
|
||||||
|
|
||||||
|
bool activate_field = true;
|
||||||
|
bool keep_field_on = true;
|
||||||
|
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||||
|
int resplen = 0;
|
||||||
|
|
||||||
|
// --------------- Select NDEF Tag application ----------------
|
||||||
|
uint8_t aSELECT_AID[80];
|
||||||
|
int aSELECT_AID_n = 0;
|
||||||
|
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||||
|
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resplen < 2) {
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_field = false;
|
||||||
|
keep_field_on = true;
|
||||||
|
// --------------- CC file reading ----------------
|
||||||
|
|
||||||
|
uint8_t aSELECT_FILE_CC[30];
|
||||||
|
int aSELECT_FILE_CC_n = 0;
|
||||||
|
param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n);
|
||||||
|
res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t aREAD_CC[30];
|
||||||
|
int aREAD_CC_n = 0;
|
||||||
|
param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n);
|
||||||
|
res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
// store st cc data for later
|
||||||
|
uint8_t st_cc_data[resplen - 2];
|
||||||
|
memcpy(st_cc_data, response, sizeof(st_cc_data));
|
||||||
|
|
||||||
|
// --------------- System file reading ----------------
|
||||||
|
uint8_t aSELECT_FILE_SYS[30];
|
||||||
|
int aSELECT_FILE_SYS_n = 0;
|
||||||
|
param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n);
|
||||||
|
res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_field_on = false;
|
||||||
|
|
||||||
|
uint8_t aREAD_SYS[30];
|
||||||
|
int aREAD_SYS_n = 0;
|
||||||
|
param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n);
|
||||||
|
res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
print_st25ta_cc_info(st_cc_data, sizeof(st_cc_data));
|
||||||
|
print_st25ta_system_info(response, resplen - 2);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// menu command to get and print all info known about any known ST25TA tag
|
||||||
|
static int CmdHFST25TAInfo(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf st25ta info",
|
||||||
|
"Get info about ST25TA tag",
|
||||||
|
"hf st25ta info"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return infoHFST25TA();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFST25TASim(const char *Cmd) {
|
||||||
|
int uidlen = 0;
|
||||||
|
uint8_t uid[7] = {0};
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf st25ta sim",
|
||||||
|
"Emulating ST25TA512B tag with 7 byte UID",
|
||||||
|
"hf st25ta sim -u 02E2007D0FCA4C\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("u", "uid", "<hex>", "7 byte UID"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (uidlen != 7) {
|
||||||
|
PrintAndLogEx(ERR, "UID must be 7 hex bytes");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
char param[40];
|
||||||
|
snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen));
|
||||||
|
return CmdHF14ASim(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdHFST25TANdefRead(const char *Cmd) {
|
||||||
|
int pwdlen = 0;
|
||||||
|
uint8_t pwd[16] = {0};
|
||||||
|
bool with_pwd = false;
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf st25ta ndefread",
|
||||||
|
"Read NFC Data Exchange Format (NDEF) file on ST25TA",
|
||||||
|
"hf st25ta ndefread -p 82E80053D4CA5C0B656D852CC696C8A1\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("p", "pwd", "<hex>", "16 byte read password"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (pwdlen == 0) {
|
||||||
|
with_pwd = false;
|
||||||
|
} else {
|
||||||
|
if (pwdlen != 16) {
|
||||||
|
PrintAndLogEx(ERR, "Password must be 16 hex bytes");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
with_pwd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool activate_field = true;
|
||||||
|
bool keep_field_on = true;
|
||||||
|
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||||
|
int resplen = 0;
|
||||||
|
|
||||||
|
// --------------- Select NDEF Tag application ----------------
|
||||||
|
uint8_t aSELECT_AID[80];
|
||||||
|
int aSELECT_AID_n = 0;
|
||||||
|
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||||
|
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resplen < 2) {
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_field = false;
|
||||||
|
keep_field_on = true;
|
||||||
|
|
||||||
|
// --------------- NDEF file reading ----------------
|
||||||
|
uint8_t aSELECT_FILE_NDEF[30];
|
||||||
|
int aSELECT_FILE_NDEF_n = 0;
|
||||||
|
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
||||||
|
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (with_pwd) {
|
||||||
|
// --------------- VERIFY ----------------
|
||||||
|
uint8_t aVERIFY[30];
|
||||||
|
int aVERIFY_n = 0;
|
||||||
|
param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||||
|
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw == 0x6300) {
|
||||||
|
// need to provide 16byte password
|
||||||
|
param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||||
|
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
||||||
|
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_field_on = false;
|
||||||
|
uint8_t aREAD_NDEF[30];
|
||||||
|
int aREAD_NDEF_n = 0;
|
||||||
|
param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
|
||||||
|
res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
NDEFRecordsDecodeAndPrint(response + 2, resplen - 4);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFST25TAProtect(const char *Cmd) {
|
||||||
|
|
||||||
|
int pwdlen = 0;
|
||||||
|
uint8_t pwd[16] = {0};
|
||||||
|
int statelen = 3;
|
||||||
|
uint8_t state[3] = {0x26, 0, 0x02};
|
||||||
|
|
||||||
|
bool disable_protection = false;
|
||||||
|
bool enable_protection = false;
|
||||||
|
bool read_protection = false;
|
||||||
|
bool write_protection = false;
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf st25ta protect",
|
||||||
|
"Change read or write protection for NFC Data Exchange Format (NDEF) file on ST25TA",
|
||||||
|
"hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -r -e -> enable read protection\n"
|
||||||
|
"hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -w -d -> disable write protection\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0("e", "enable", "enable protection"),
|
||||||
|
arg_lit0("d", "disable", "disable protection (default)"),
|
||||||
|
arg_lit0("r", "read", "change read protection"),
|
||||||
|
arg_lit0("w", "write", "change write protection (default)"),
|
||||||
|
arg_str1("p", "password", "<hex>", "16 byte write password"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
enable_protection = arg_get_lit(ctx, 1);
|
||||||
|
disable_protection = arg_get_lit(ctx, 2);
|
||||||
|
read_protection = arg_get_lit(ctx, 3);
|
||||||
|
write_protection = arg_get_lit(ctx, 4);
|
||||||
|
CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
//Validations
|
||||||
|
if (enable_protection && disable_protection) {
|
||||||
|
PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (enable_protection) {
|
||||||
|
state[0] = 0x28;
|
||||||
|
}
|
||||||
|
if (disable_protection) {
|
||||||
|
state[0] = 0x26;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_protection && write_protection) {
|
||||||
|
PrintAndLogEx(ERR, "Must specify either read or write protection, not both");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (read_protection) {
|
||||||
|
state[2] = 0x01;
|
||||||
|
}
|
||||||
|
if (write_protection) {
|
||||||
|
state[2] = 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwdlen != 16) {
|
||||||
|
PrintAndLogEx(ERR, "Missing 16 byte password");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool activate_field = true;
|
||||||
|
bool keep_field_on = true;
|
||||||
|
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||||
|
int resplen = 0;
|
||||||
|
|
||||||
|
// --------------- Select NDEF Tag application ----------------
|
||||||
|
uint8_t aSELECT_AID[80];
|
||||||
|
int aSELECT_AID_n = 0;
|
||||||
|
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||||
|
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resplen < 2) {
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_field = false;
|
||||||
|
keep_field_on = true;
|
||||||
|
|
||||||
|
// --------------- Select NDEF file ----------------
|
||||||
|
uint8_t aSELECT_FILE_NDEF[30];
|
||||||
|
int aSELECT_FILE_NDEF_n = 0;
|
||||||
|
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
||||||
|
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------- VERIFY ----------------
|
||||||
|
uint8_t aVERIFY[30];
|
||||||
|
int aVERIFY_n = 0;
|
||||||
|
// need to provide 16byte password
|
||||||
|
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||||
|
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
||||||
|
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------- Change protection ----------------
|
||||||
|
keep_field_on = false;
|
||||||
|
uint8_t aPROTECT[30];
|
||||||
|
int aPROTECT_n = 0;
|
||||||
|
param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n);
|
||||||
|
memcpy(aPROTECT + aPROTECT_n, state, statelen);
|
||||||
|
res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"),
|
||||||
|
((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled"));
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFST25TAPwd(const char *Cmd) {
|
||||||
|
|
||||||
|
int pwdlen = 0;
|
||||||
|
uint8_t pwd[16] = {0};
|
||||||
|
int newpwdlen = 0;
|
||||||
|
uint8_t newpwd[16] = {0};
|
||||||
|
int changePwdlen = 4;
|
||||||
|
uint8_t changePwd[4] = {0x24, 0x00, 0x01, 0x10};
|
||||||
|
bool change_read_password = false;
|
||||||
|
bool change_write_password = false;
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf st25ta pwd",
|
||||||
|
"Change read or write password for NFC Data Exchange Format (NDEF) file on ST25TA",
|
||||||
|
"hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -r -n 00000000000000000000000000000000 -> change read password\n"
|
||||||
|
"hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -w -n 00000000000000000000000000000000 -> change write password\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0("r", "read", "change the read password (default)"),
|
||||||
|
arg_lit0("w", "write", "change the write password"),
|
||||||
|
arg_str1("p", "password", "<hex>", "current 16 byte write password"),
|
||||||
|
arg_str1("n", "new", "<hex>", "new 16 byte password"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
change_read_password = arg_get_lit(ctx, 1);
|
||||||
|
change_write_password = arg_get_lit(ctx, 2);
|
||||||
|
CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen);
|
||||||
|
CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (change_read_password && change_write_password) {
|
||||||
|
PrintAndLogEx(ERR, "Must specify either read or write, not both");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (change_read_password) {
|
||||||
|
changePwd[2] = 0x01;
|
||||||
|
}
|
||||||
|
if (change_write_password) {
|
||||||
|
changePwd[2] = 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwdlen != 16) {
|
||||||
|
PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (newpwdlen != 16) {
|
||||||
|
PrintAndLogEx(ERR, "New password must be 16 hex bytes");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool activate_field = true;
|
||||||
|
bool keep_field_on = true;
|
||||||
|
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||||
|
int resplen = 0;
|
||||||
|
|
||||||
|
// --------------- Select NDEF Tag application ----------------
|
||||||
|
uint8_t aSELECT_AID[80];
|
||||||
|
int aSELECT_AID_n = 0;
|
||||||
|
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||||
|
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resplen < 2) {
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_field = false;
|
||||||
|
keep_field_on = true;
|
||||||
|
|
||||||
|
// --------------- Select NDEF file ----------------
|
||||||
|
uint8_t aSELECT_FILE_NDEF[30];
|
||||||
|
int aSELECT_FILE_NDEF_n = 0;
|
||||||
|
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
||||||
|
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------- VERIFY ----------------
|
||||||
|
uint8_t aVERIFY[30];
|
||||||
|
int aVERIFY_n = 0;
|
||||||
|
// need to provide 16byte password
|
||||||
|
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||||
|
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
||||||
|
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------- Change password ----------------
|
||||||
|
|
||||||
|
keep_field_on = false;
|
||||||
|
uint8_t aCHG_PWD[30];
|
||||||
|
int aCHG_PWD_n = 0;
|
||||||
|
param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n);
|
||||||
|
memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen);
|
||||||
|
memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen);
|
||||||
|
res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
DropField();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw = get_sw(response, resplen);
|
||||||
|
if (sw != 0x9000) {
|
||||||
|
PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"));
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFST25TAList(const char *Cmd) {
|
||||||
|
return CmdTraceListAlias(Cmd, "hf st25ta", "7816");
|
||||||
|
}
|
||||||
|
|
||||||
|
static command_t CommandTable[] = {
|
||||||
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
{"info", CmdHFST25TAInfo, IfPm3Iso14443a, "Tag information"},
|
||||||
|
{"list", CmdHFST25TAList, AlwaysAvailable, "List ISO 14443A/7816 history"},
|
||||||
|
{"ndefread", CmdHFST25TANdefRead, AlwaysAvailable, "read NDEF file on tag"},
|
||||||
|
{"protect", CmdHFST25TAProtect, IfPm3Iso14443a, "change protection on tag"},
|
||||||
|
{"pwd", CmdHFST25TAPwd, IfPm3Iso14443a, "change password on tag"},
|
||||||
|
{"sim", CmdHFST25TASim, IfPm3Iso14443a, "Fake ISO 14443A/ST tag"},
|
||||||
|
{NULL, NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd) {
|
||||||
|
(void)Cmd; // Cmd is not used so far
|
||||||
|
CmdsHelp(CommandTable);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdHFST25TA(const char *Cmd) {
|
||||||
|
clearCommandBuffer();
|
||||||
|
return CmdsParse(CommandTable, Cmd);
|
||||||
|
}
|
19
client/src/cmdhfst25ta.h
Normal file
19
client/src/cmdhfst25ta.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2020 iceman1001
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// High frequency ISO14443A / ST25TA commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CMDHFST25TA_H__
|
||||||
|
#define CMDHFST25TA_H__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int CmdHFST25TA(const char *Cmd);
|
||||||
|
int CmdHFST25TANdefRead(const char *Cmd);
|
||||||
|
|
||||||
|
#endif
|
|
@ -15,7 +15,7 @@
|
||||||
#include "cmdhfmf.h"
|
#include "cmdhfmf.h"
|
||||||
#include "cmdhfmfp.h"
|
#include "cmdhfmfp.h"
|
||||||
#include "cmdhfmfu.h"
|
#include "cmdhfmfu.h"
|
||||||
#include "cmdhfst.h"
|
#include "cmdhfst25ta.h"
|
||||||
#include "cmdhfthinfilm.h"
|
#include "cmdhfthinfilm.h"
|
||||||
#include "cmdhftopaz.h"
|
#include "cmdhftopaz.h"
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ static int CmdNFCType4ARead(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdNFCST25TARead(const char *Cmd) {
|
static int CmdNFCST25TARead(const char *Cmd) {
|
||||||
return CmdHFSTNdefRead(Cmd);
|
return CmdHFST25TANdefRead(Cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdNFCType4AHelp(const char *Cmd);
|
static int CmdNFCType4AHelp(const char *Cmd);
|
||||||
|
|
|
@ -518,19 +518,19 @@ Check column "offline" for their availability.
|
||||||
|`hf seos list `|Y |`List SEOS history`
|
|`hf seos list `|Y |`List SEOS history`
|
||||||
|
|
||||||
|
|
||||||
### hf st
|
### hf st25ta
|
||||||
|
|
||||||
{ ST Rothult RFIDs... }
|
{ ST25TA RFIDs... }
|
||||||
|
|
||||||
|command |offline |description
|
|command |offline |description
|
||||||
|------- |------- |-----------
|
|------- |------- |-----------
|
||||||
|`hf st help `|Y |`This help`
|
|`hf st25ta help `|Y |`This help`
|
||||||
|`hf st info `|N |`Tag information`
|
|`hf st25ta info `|N |`Tag information`
|
||||||
|`hf st list `|Y |`List ISO 14443A/7816 history`
|
|`hf st25ta list `|Y |`List ISO 14443A/7816 history`
|
||||||
|`hf st ndefread `|Y |`read NDEF file on tag`
|
|`hf st25ta ndefread `|Y |`read NDEF file on tag`
|
||||||
|`hf st protect `|N |`change protection on tag`
|
|`hf st25ta protect `|N |`change protection on tag`
|
||||||
|`hf st pwd `|N |`change password on tag`
|
|`hf st25ta pwd `|N |`change password on tag`
|
||||||
|`hf st sim `|N |`Fake ISO 14443A/ST tag`
|
|`hf st25ta sim `|N |`Fake ISO 14443A/ST tag`
|
||||||
|
|
||||||
|
|
||||||
### hf thinfilm
|
### hf thinfilm
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue