Merge pull request #3427 from Sanduuz/feature/st25ta_ndef_sim

Added support for emulating ST25TA tag (IKEA Rothult) with custom NDEF response
This commit is contained in:
Iceman
2026-09-07 15:38:46 +07:00
committed by GitHub
8 changed files with 488 additions and 14 deletions
+1
View File
@@ -81,6 +81,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fixed `hf_mf_uscuid_prog.lua` - corrected the script name shown in its usage text (@c-barron)
- Added `hf felica seacauth1` command (@kormax)
- Added `lf trovan` commands to support Trovan Animal ID (@iceman1001)
- Added support for emulating ST25TA tag (IKEA Rothult) with custom NDEF response (@sanduuz)
- Added `hf mf gdmgetblk/gdmgethidblk/gdmsethidblk/gdmsetuid/gdmwipe/gdmsetsig` (@0x6r1an0y)
- Changed `hf mf gdmparsecfg/gdmsetblk` (@0x6r1an0y)
- Renamed `hf mf gdmcfg` (@0x6r1an0y)
+1
View File
@@ -27,6 +27,7 @@
#include "bwm_forward.h" // bwm_fwd_negotiate_baud()
#include "bwm_wifi.h"
#endif
#include "pm3_cmd.h"
#include "proxmark3_arm.h"
#include "dbprint.h"
#include "pmflash.h"
+43 -5
View File
@@ -19,6 +19,7 @@
//-----------------------------------------------------------------------------
#include "iso14443a.h"
#include "pm3_cmd.h"
#include "string.h"
#include "proxmark3_arm.h"
#include "cmd.h"
@@ -1776,13 +1777,20 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
uint8_t *dynamic_response_buffer = BigBuf_calloc(DYNAMIC_RESPONSE_BUFFER_SIZE);
uint16_t dynamic_response_buffer_size = DYNAMIC_RESPONSE_BUFFER_SIZE;
uint16_t dynamic_modulation_buffer_size = DYNAMIC_MODULATION_BUFFER_SIZE;
if (tagType == 10) {
dynamic_response_buffer_size = ST25TA_EML_NDEF_MAX + 4;
dynamic_modulation_buffer_size = 4096;
}
uint8_t *dynamic_response_buffer = BigBuf_calloc(dynamic_response_buffer_size);
if (dynamic_response_buffer == NULL) {
BigBuf_free_keep_EM();
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EMALLOC, NULL, 0);
return;
}
uint8_t *dynamic_modulation_buffer = BigBuf_calloc(DYNAMIC_MODULATION_BUFFER_SIZE);
uint8_t *dynamic_modulation_buffer = BigBuf_calloc(dynamic_modulation_buffer_size);
if (dynamic_modulation_buffer == NULL) {
BigBuf_free_keep_EM();
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EMALLOC, NULL, 0);
@@ -1803,6 +1811,22 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
return;
}
uint8_t st25ta_ndef[ST25TA_EML_NDEF_MAX] = {0};
uint16_t st25ta_ndef_len = 0;
if (tagType == 10) {
uint8_t st25ta_header[ST25TA_EML_DATA_OFFSET] = {0};
emlGet(st25ta_header, 0, sizeof(st25ta_header));
if (memcmp(st25ta_header + ST25TA_EML_MAGIC_OFFSET, ST25TA_EML_MAGIC, 4) == 0) {
st25ta_ndef_len = st25ta_header[ST25TA_EML_LEN_OFFSET] |
(st25ta_header[ST25TA_EML_LEN_OFFSET + 1] << 8);
if (st25ta_ndef_len <= ST25TA_EML_NDEF_MAX) {
emlGet(st25ta_ndef, ST25TA_EML_DATA_OFFSET, st25ta_ndef_len);
} else {
st25ta_ndef_len = 0;
}
}
}
mfu_dump_t *mfu_em_dump = NULL;
if (tagType == 2 || tagType == 7) {
mfu_em_dump = (mfu_dump_t *)BigBuf_get_EM_addr();
@@ -2448,10 +2472,24 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
if (tagType == 10) {
// we replay 90 00 for all commands but the read bin and we deny the verify cmd.
static const uint8_t default_st25ta_ndef[] = {
0x00, 0x1b, 0xd1, 0x01, 0x17, 0x54, 0x02, 0x7a,
0x68, 0xa2, 0x34, 0xcb, 0xd0, 0xe2, 0x03, 0xc7,
0x3e, 0x62, 0x0b, 0xe8, 0xc6, 0x3c, 0x85, 0x2c,
0xc5, 0x31, 0x31, 0x31, 0x32, 0x90, 0x00
};
const uint8_t *ndef = default_st25ta_ndef;
uint16_t ndef_len = sizeof(default_st25ta_ndef);
if (st25ta_ndef_len > 0) {
ndef = st25ta_ndef;
ndef_len = st25ta_ndef_len;
}
if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) {
dynamic_response_info.response[0] = receivedCmd[0];
memcpy(dynamic_response_info.response + 1, "\x00\x1b\xd1\x01\x17\x54\x02\x7a\x68\xa2\x34\xcb\xd0\xe2\x03\xc7\x3e\x62\x0b\xe8\xc6\x3c\x85\x2c\xc5\x31\x31\x31\x32\x90\x00", 31);
dynamic_response_info.response_n = 32;
memcpy(dynamic_response_info.response + 1, ndef, ndef_len);
dynamic_response_info.response_n = ndef_len + 1;
} else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) {
dynamic_response_info.response[0] = receivedCmd[0];
dynamic_response_info.response[1] = 0x63;
@@ -2546,7 +2584,7 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
dynamic_response_info.response_n += 2;
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
if (prepare_tag_modulation(&dynamic_response_info, dynamic_modulation_buffer_size) == false) {
if (g_dbglevel >= DBG_DEBUG) DbpString("Error preparing tag response");
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
break;
+1
View File
@@ -1106,6 +1106,7 @@ int CmdHF14ASim(const char *Cmd) {
bool ulauth_1a2_mirror;
} PACKED payload;
memset(&payload, 0x00, sizeof(payload));
payload.tagtype = tagtype;
payload.flags = flags;
payload.exitAfter = exitAfterNReads;
+378 -4
View File
@@ -26,6 +26,7 @@
#include "cliparser.h"
#include "crc16.h"
#include "cmdhf14a.h"
#include "pm3_cmd.h"
#include "protocols.h" // definitions of ISO14A/7816 protocol
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
@@ -34,6 +35,8 @@
#include "protocols.h" // ISO7816 APDU return codes
#include "crypto/libpcrypto.h" // ecdsa
#include "crypto/originality.h"
#include "mifare/mifarehost.h" // mf_eml_set_mem_xt / mf_eml_get_mem_xt
#include "ui.h"
#define TIMEOUT 2000
@@ -335,29 +338,397 @@ static int CmdHFST25TAInfo(const char *Cmd) {
return infoHFST25TA();
}
static int st25ta_ndef_records_len(const uint8_t *data, size_t data_len, size_t *records_len) {
if (data == NULL || records_len == NULL || data_len < 3) {
return PM3_EINVARG;
}
size_t offset = 0;
for (;;) {
if (offset + 3 > data_len) {
return PM3_ESOFT;
}
uint8_t flags = data[offset];
uint8_t type_len = data[offset + 1];
bool short_record = (flags & 0x10) != 0;
bool id_length_present = (flags & 0x08) != 0;
bool message_end = (flags & 0x40) != 0;
size_t header_len = short_record ? 3 : 6;
uint32_t payload_len = 0;
if (short_record) {
payload_len = data[offset + 2];
} else {
if (offset + 6 > data_len) {
return PM3_ESOFT;
}
payload_len = (data[offset + 2] << 24) |
(data[offset + 3] << 16) |
(data[offset + 4] << 8) |
data[offset + 5];
}
uint8_t id_len = 0;
if (id_length_present) {
if (offset + header_len >= data_len) {
return PM3_ESOFT;
}
id_len = data[offset + header_len];
header_len++;
}
size_t record_len = header_len + type_len + id_len + payload_len;
if (record_len == 0 || offset + record_len > data_len) {
return PM3_ESOFT;
}
offset += record_len;
if (message_end) {
*records_len = offset;
return PM3_SUCCESS;
}
}
}
static int st25ta_normalize_sim_ndef(const uint8_t *src, size_t src_len, uint8_t *dst, uint16_t *dst_len) {
if (src == NULL || src_len == 0 || dst == NULL || dst_len == NULL) {
return PM3_EINVARG;
}
if (src_len >= 4 && src[src_len - 2] == 0x90 && src[src_len - 1] == 0x00) {
uint16_t nlen = (src[0] << 8) | src[1];
if (nlen + 4 != src_len) {
nlen = src_len - 4;
}
if (src_len > ST25TA_EML_NDEF_MAX) {
PrintAndLogEx(ERR, "NDEF response too large. Max %u bytes", ST25TA_EML_NDEF_MAX);
return PM3_EINVARG;
}
dst[0] = (nlen >> 8) & 0xff;
dst[1] = nlen & 0xff;
memcpy(dst + 2, src + 2, src_len - 4);
dst[src_len - 2] = 0x90;
dst[src_len - 1] = 0x00;
*dst_len = src_len;
return PM3_SUCCESS;
}
if (src_len >= 2) {
uint16_t nlen = (src[0] << 8) | src[1];
if (nlen + 2 == src_len) {
if (src_len + 2 > ST25TA_EML_NDEF_MAX) {
PrintAndLogEx(ERR, "NDEF response too large. Max %u bytes", ST25TA_EML_NDEF_MAX);
return PM3_EINVARG;
}
dst[0] = (nlen >> 8) & 0xff;
dst[1] = nlen & 0xff;
memcpy(dst + 2, src + 2, nlen);
dst[src_len] = 0x90;
dst[src_len + 1] = 0x00;
*dst_len = src_len + 2;
return PM3_SUCCESS;
}
}
if (src_len + 4 > ST25TA_EML_NDEF_MAX) {
PrintAndLogEx(ERR, "NDEF response too large. Max %u bytes", ST25TA_EML_NDEF_MAX);
return PM3_EINVARG;
}
dst[0] = (src_len >> 8) & 0xff;
dst[1] = src_len & 0xff;
memcpy(dst + 2, src, src_len);
dst[src_len + 2] = 0x90;
dst[src_len + 3] = 0x00;
*dst_len = src_len + 4;
return PM3_SUCCESS;
}
static int st25ta_upload_sim_data(const uint8_t *uid, uint8_t uid_len, const uint8_t *ndef, uint16_t ndef_len) {
uint8_t data[ST25TA_EML_DATA_OFFSET + ST25TA_EML_NDEF_MAX] = {0};
uint16_t data_len = ST25TA_EML_DATA_OFFSET + ndef_len;
memcpy(data + ST25TA_EML_MAGIC_OFFSET, ST25TA_EML_MAGIC, 4);
data[ST25TA_EML_LEN_OFFSET] = ndef_len & 0xff;
data[ST25TA_EML_LEN_OFFSET + 1] = (ndef_len >> 8) & 0xff;
data[ST25TA_EML_UIDLEN_OFFSET] = uid_len;
if (uid_len == 7) {
memcpy(data + ST25TA_EML_UID_OFFSET, uid, uid_len);
}
memcpy(data + ST25TA_EML_DATA_OFFSET, ndef, ndef_len);
for (uint16_t offset = 0; offset < data_len;) {
uint8_t chunk_len = MIN(data_len - offset, UINT8_MAX);
int res = mf_eml_set_mem_xt(data + offset, offset, chunk_len, 1);
if (res != PM3_SUCCESS) {
return res;
}
offset += chunk_len;
}
return PM3_SUCCESS;
}
static int st25ta_download_sim_data(uint8_t *uid, uint8_t *uid_len, uint8_t *ndef, uint16_t *ndef_len) {
uint8_t header[ST25TA_EML_DATA_OFFSET] = {0};
int res = mf_eml_get_mem_xt(header, 0, sizeof(header), 1);
if (res != PM3_SUCCESS) {
return res;
}
if (memcmp(header + ST25TA_EML_MAGIC_OFFSET, ST25TA_EML_MAGIC, 4) != 0) {
PrintAndLogEx(ERR, "No ST25TA data loaded in emulator memory");
return PM3_ESOFT;
}
uint16_t len = header[ST25TA_EML_LEN_OFFSET] |
(header[ST25TA_EML_LEN_OFFSET + 1] << 8);
if (len == 0 || len > ST25TA_EML_NDEF_MAX) {
PrintAndLogEx(ERR, "Invalid ST25TA NDEF response length in emulator memory: %u", len);
return PM3_ESOFT;
}
if (uid_len != NULL) {
*uid_len = header[ST25TA_EML_UIDLEN_OFFSET];
}
if (uid != NULL && header[ST25TA_EML_UIDLEN_OFFSET] == 7) {
memcpy(uid, header + ST25TA_EML_UID_OFFSET, 7);
}
for (uint16_t offset = 0; offset < len;) {
uint8_t chunk_len = MIN(len - offset, UINT8_MAX);
res = mf_eml_get_mem_xt(ndef + offset, ST25TA_EML_DATA_OFFSET + offset, chunk_len, 1);
if (res != PM3_SUCCESS) {
return res;
}
offset += chunk_len;
}
*ndef_len = len;
return PM3_SUCCESS;
}
static int CmdHFST25TAELoad(const char *Cmd) {
int uidlen = 0;
uint8_t uid[7] = {0};
int ndef_hex_len = 0;
uint8_t ndef_hex[ST25TA_EML_NDEF_MAX] = {0};
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st25ta eload",
"Load ST25TA NDEF response into emulator memory",
"hf st25ta eload --ndef 001BD1011754027A68A234CBD0E203C73E620BE8C63C852CC5313131329000\n"
"hf st25ta eload -f my-ndef.bin\n"
"hf st25ta eload -u 02E2007D0FCA4C -f my-ndef.bin\n");
void *argtable[] = {
arg_param_begin,
arg_str0("u", "uid", "<hex>", "optional 7 byte UID to store for simulation"),
arg_str0(NULL, "ndef", "<hex>", "NDEF data or full READ BINARY response"),
arg_str0("f", "file", "<fn>", "load NDEF data or full READ BINARY response from file"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
int ndef_res = CLIParamHexToBuf(arg_get_str(ctx, 2), ndef_hex, sizeof(ndef_hex), &ndef_hex_len);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
if (uidlen != 0 && uidlen != 7) {
PrintAndLogEx(ERR, "UID must be 7 hex bytes");
return PM3_EINVARG;
}
if (ndef_res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Invalid NDEF hex");
return ndef_res;
}
if ((ndef_hex_len > 0) == (fnlen > 0)) {
PrintAndLogEx(ERR, "Use exactly one of --ndef or -f");
return PM3_EINVARG;
}
uint8_t ndef[ST25TA_EML_NDEF_MAX] = {0};
uint16_t ndef_len = 0;
if (ndef_hex_len > 0) {
int res = st25ta_normalize_sim_ndef(ndef_hex, ndef_hex_len, ndef, &ndef_len);
if (res != PM3_SUCCESS) {
return res;
}
} else {
uint8_t *file_data = NULL;
size_t file_len = 0;
int res = loadFile_safe(filename, "", (void **)&file_data, &file_len);
if (res != PM3_SUCCESS) {
return res;
}
res = st25ta_normalize_sim_ndef(file_data, file_len, ndef, &ndef_len);
free(file_data);
if (res != PM3_SUCCESS) {
return res;
}
}
int res = st25ta_upload_sim_data(uid, uidlen, ndef, ndef_len);
if (res != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Failed uploading ST25TA data to emulator memory");
return res;
}
PrintAndLogEx(SUCCESS, "Uploaded ST25TA NDEF response to emulator memory (" _YELLOW_("%u") " bytes)", ndef_len);
if (uidlen == 7) {
PrintAndLogEx(SUCCESS, "Stored UID " _YELLOW_("%s"), sprint_hex_inrow(uid, uidlen));
}
PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf st25ta sim`"));
return PM3_SUCCESS;
}
static int CmdHFST25TAEView(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st25ta eview",
"Display ST25TA emulator memory",
"hf st25ta eview\n"
"hf st25ta eview -v\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("v", "verbose", "verbose NDEF output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool verbose = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
uint8_t uid[7] = {0};
uint8_t uid_len = 0;
uint8_t ndef[ST25TA_EML_NDEF_MAX] = {0};
uint16_t ndef_len = 0;
int res = st25ta_download_sim_data(uid, &uid_len, ndef, &ndef_len);
if (res != PM3_SUCCESS) {
return res;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("ST25TA emulator memory") " ----------------");
if (uid_len == 7) {
PrintAndLogEx(INFO, "UID................ " _YELLOW_("%s"), sprint_hex_inrow(uid, uid_len));
} else {
PrintAndLogEx(INFO, "UID................ " _YELLOW_("not loaded"));
}
PrintAndLogEx(INFO, "NDEF response len.. " _YELLOW_("%u") " bytes", ndef_len);
PrintAndLogEx(INFO, "NDEF response raw:");
print_buffer(ndef, ndef_len, 1);
if (ndef_len >= 4 && ndef[ndef_len - 2] == 0x90 && ndef[ndef_len - 1] == 0x00) {
uint16_t nlen = (ndef[0] << 8) | ndef[1];
size_t records_len = ndef_len - 4;
if (nlen <= records_len) {
records_len = nlen;
}
size_t calculated_len = 0;
if (st25ta_ndef_records_len(ndef + 2, records_len, &calculated_len) == PM3_SUCCESS &&
calculated_len < records_len) {
records_len = calculated_len;
}
PrintAndLogEx(INFO, "--- " _CYAN_("NDEF records") " --------------------------");
NDEFRecordsDecodeAndPrint(ndef + 2, records_len, verbose);
}
return PM3_SUCCESS;
}
static int CmdHFST25TAESave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st25ta esave",
"Save ST25TA emulator memory NDEF response to file",
"hf st25ta esave\n"
"hf st25ta esave -f hf-st25ta-ndef\n");
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
char filename[FILE_PATH_SIZE] = {0};
int fnlen = 0;
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
if (fnlen == 0) {
snprintf(filename, sizeof(filename), "hf-st25ta-ndef");
}
uint8_t ndef[ST25TA_EML_NDEF_MAX] = {0};
uint16_t ndef_len = 0;
int res = st25ta_download_sim_data(NULL, NULL, ndef, &ndef_len);
if (res != PM3_SUCCESS) {
return res;
}
if (ndef_len < 4 || ndef[ndef_len - 2] != 0x90 || ndef[ndef_len - 1] != 0x00) {
PrintAndLogEx(ERR, "Loaded ST25TA data is not a READ BINARY response ending in 9000");
return PM3_ESOFT;
}
uint16_t nlen = (ndef[0] << 8) | ndef[1];
if (nlen == 0 || nlen + 4 > ndef_len) {
PrintAndLogEx(ERR, "Invalid ST25TA NLEN in emulator memory: %u", nlen);
return PM3_ESOFT;
}
return pm3_save_dump(filename, ndef + 2, nlen, jsfNDEF);
}
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");
"Emulating ST25TA512B tag. Uses NDEF data from `hf st25ta eload` if loaded.",
"hf st25ta sim -u 02E2007D0FCA4C\n"
"hf st25ta sim\n");
void *argtable[] = {
arg_param_begin,
arg_str1("u", "uid", "<hex>", "7 byte UID"),
arg_str0("u", "uid", "<hex>", "7 byte UID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
CLIParserFree(ctx);
if (uidlen != 7) {
if (uidlen != 0 && uidlen != 7) {
PrintAndLogEx(ERR, "UID must be 7 hex bytes");
return PM3_EINVARG;
}
if (uidlen == 0) {
uint8_t header[ST25TA_EML_DATA_OFFSET] = {0};
int res = mf_eml_get_mem_xt(header, 0, sizeof(header), 1);
if (res != PM3_SUCCESS) {
return res;
}
if (memcmp(header + ST25TA_EML_MAGIC_OFFSET, ST25TA_EML_MAGIC, 4) == 0 &&
header[ST25TA_EML_UIDLEN_OFFSET] == 7) {
memcpy(uid, header + ST25TA_EML_UID_OFFSET, sizeof(uid));
uidlen = sizeof(uid);
} else {
PrintAndLogEx(ERR, "No UID supplied and no UID loaded. Use " _YELLOW_("`hf st25ta sim -u <uid>`") " or " _YELLOW_("`hf st25ta eload -u <uid> ...`"));
return PM3_EINVARG;
}
}
char param[40];
snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen));
return CmdHF14ASim(param);
@@ -811,6 +1182,9 @@ static int CmdHFST25TAList(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"eload", CmdHFST25TAELoad, IfPm3Iso14443a, "Upload NDEF response into emulator memory"},
{"esave", CmdHFST25TAESave, IfPm3Iso14443a, "Save emulator memory to file"},
{"eview", CmdHFST25TAEView, IfPm3Iso14443a, "View emulator memory"},
{"info", CmdHFST25TAInfo, IfPm3Iso14443a, "Tag information"},
{"list", CmdHFST25TAList, AlwaysAvailable, "List ISO 14443A/7816 history"},
{"ndefread", CmdHFST25TANdefRead, AlwaysAvailable, "read NDEF file on tag"},
+51 -5
View File
@@ -10231,13 +10231,58 @@
],
"usage": "hf sniff [-h] [--sp <dec>] [--st <dec>] [--smode [none|drop|min|max|avg]] [--sratio <dec, ms>]"
},
"hf st25ta esave": {
"command": "hf st25ta esave",
"description": "Save ST25TA emulator memory NDEF response to file",
"notes": [
"hf st25ta esave",
"hf st25ta esave -f hf-st25ta-ndef"
],
"offline": false,
"options": [
"-h, --help This help",
"-f, --file <fn> Specify a filename for dump file"
],
"usage": "hf st25ta esave [-h] [-f <fn>]"
},
"hf st25ta eview": {
"command": "hf st25ta eview",
"description": "Display ST25TA emulator memory",
"notes": [
"hf st25ta eview",
"hf st25ta eview -v"
],
"offline": false,
"options": [
"-h, --help This help",
"-v, --verbose verbose NDEF output"
],
"usage": "hf st25ta eview [-hv]"
},
"hf st25ta help": {
"command": "hf st25ta help",
"description": "help This help list List ISO 14443A/7816 history ndefread read NDEF file on tag --------------------------------------------------------------------------------------- hf st25ta info available offline: no Get info about ST25TA tag",
"description": "help This help list List ISO 14443A/7816 history ndefread read NDEF file on tag --------------------------------------------------------------------------------------- hf st25ta eload available offline: no Load ST25TA NDEF response into emulator memory",
"notes": [
"hf st25ta eload --ndef 001BD1011754027A68A234CBD0E203C73E620BE8C63C852CC5313131329000",
"hf st25ta eload -f my-ndef.bin",
"hf st25ta eload -u 02E2007D0FCA4C -f my-ndef.bin"
],
"offline": true,
"options": [
"-h, --help This help",
"-u, --uid <hex> optional 7 byte UID to store for simulation",
"--ndef <hex> NDEF data or full READ BINARY response",
"-f, --file <fn> load NDEF data or full READ BINARY response from file"
],
"usage": "hf st25ta eload [-h] [-u <hex>] [--ndef <hex>] [-f <fn>]"
},
"hf st25ta info": {
"command": "hf st25ta info",
"description": "Get info about ST25TA tag",
"notes": [
"hf st25ta info"
],
"offline": true,
"offline": false,
"options": [
"-h, --help This help"
],
@@ -10317,16 +10362,17 @@
},
"hf st25ta sim": {
"command": "hf st25ta sim",
"description": "Emulating ST25TA512B tag with 7 byte UID",
"description": "Emulating ST25TA512B tag. Uses NDEF data from `hf st25ta eload` if loaded.",
"notes": [
"hf st25ta sim -u 02E2007D0FCA4C"
"hf st25ta sim -u 02E2007D0FCA4C",
"hf st25ta sim"
],
"offline": false,
"options": [
"-h, --help This help",
"-u, --uid <hex> 7 byte UID"
],
"usage": "hf st25ta sim [-h] -u <hex>"
"usage": "hf st25ta sim [-h] [-u <hex>]"
},
"hf tesla help": {
"command": "hf tesla help",
+3
View File
@@ -896,6 +896,9 @@ Check column "offline" for their availability.
|command |offline |description
|------- |------- |-----------
|`hf st25ta help `|Y |`This help`
|`hf st25ta eload `|N |`Upload NDEF response into emulator memory`
|`hf st25ta esave `|N |`Save emulator memory to file`
|`hf st25ta eview `|N |`View emulator memory`
|`hf st25ta info `|N |`Tag information`
|`hf st25ta list `|Y |`List ISO 14443A/7816 history`
|`hf st25ta ndefread `|Y |`read NDEF file on tag`
+10
View File
@@ -1209,6 +1209,16 @@ typedef struct {
#define CMD_UNKNOWN 0xFFFF
// ST25TA simulation data in emulator memory:
// magic[4] || len_le[2] || uid_len[1] || uid[7] || READ BINARY response bytes
#define ST25TA_EML_MAGIC_OFFSET 0
#define ST25TA_EML_LEN_OFFSET 4
#define ST25TA_EML_UIDLEN_OFFSET 6
#define ST25TA_EML_UID_OFFSET 7
#define ST25TA_EML_DATA_OFFSET 14
#define ST25TA_EML_NDEF_MAX 256
#define ST25TA_EML_MAGIC "ST25"
// Mifare simulation flags
// In interactive mode, we are expected to finish the operation with an ACK
#define FLAG_INTERACTIVE 0x0001