New individual json dump file formats for ht1, ht2, htS, htU. '.bin' / binary format for hitag has been deprecated

This commit is contained in:
iceman1001 committed 2026-08-29 20:58:59 +02:00
1 parent dda9d7dd1c
commit a1053ad70d
6 files changed
+114 -13

No files matched your search

+1
View File
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Added individual json dump formats for ht2, ht1, htS, htU. No more .bin files either for hitag (@iceman1001)
- Change NG: iso14a_raw_cmd_t, convert hf 14a raw, dual-mode reader handler (@iceman1001)
- Support for flipper ISO15693.nfc dump files (@iceman100)
- Change NG: convert CMD_LF_EM4X50_ESET to em4x50_eset_t (@iceman1001)
+18 -3
View File
@@ -1585,7 +1585,7 @@ out:
FillFileNameByUID(fptr, data, "-dump", HITAG_UID_SIZE);
}
pm3_save_dump(filename, data, HITAG2_MAX_BYTE_SIZE, jsfHitag);
pm3_save_dump(filename, data, HITAG2_MAX_BYTE_SIZE, jsfHitag2);
return PM3_SUCCESS;
}
@@ -1763,13 +1763,15 @@ static int CmdLFHitagSim(const char *Cmd) {
CLIParserInit(&ctx, "lf hitag sim",
"Simulate Hitag transponder\n"
"You need to `lf hitag eload` first",
"lf hitag sim -2"
"lf hitag sim -2\n"
"lf hitag sim -2 -t 30 -> set edge detect threshold to 30"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("1", "ht1", "simulate Hitag 1"),
arg_lit0("2", "ht2", "simulate Hitag 2"),
arg_int0("t", "threshold", "<dec>", "set edge detect threshold (def: 127)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -1777,8 +1779,14 @@ static int CmdLFHitagSim(const char *Cmd) {
bool use_ht1 = arg_get_lit(ctx, 1);
bool use_ht2 = arg_get_lit(ctx, 2);
bool use_htm = false; // not implemented yet
int threshold = arg_get_int_def(ctx, 3, 127);
CLIParserFree(ctx);
if (threshold < 0 || threshold > 255) {
PrintAndLogEx(ERR, "error, threshold must be 0..255");
return PM3_EINVARG;
}
if ((use_ht1 + use_ht2 + use_htm) > 1) {
PrintAndLogEx(ERR, "error, specify only one Hitag type");
return PM3_EINVARG;
@@ -1792,8 +1800,15 @@ static int CmdLFHitagSim(const char *Cmd) {
// if (use_ht1)
// cmd = CMD_LF_HITAG1_SIMULATE;
// the tag content comes from emulator memory, this only carries the threshold
hitag_sim_t payload = {
.tag_mem_supplied = false,
.rfu = 0,
.threshold = (uint16_t)threshold,
};
clearCommandBuffer();
SendCommandNG(cmd, NULL, 0);
SendCommandNG(cmd, (uint8_t *)&payload, sizeof(payload));
return PM3_SUCCESS;
}
+1 -1
View File
@@ -650,7 +650,7 @@ static int CmdLFHitagSDump(const char *Cmd) {
FillFileNameByUID(fptr, card->pages[HITAGS_UID_PADR], "-dump", HITAGS_PAGE_SIZE);
}
pm3_save_dump(filename, (uint8_t *)card->pages, mem_size, jsfHitag);
pm3_save_dump(filename, (uint8_t *)card->pages, mem_size, jsfHitagS);
return PM3_SUCCESS;
}
+14 -1
View File
@@ -494,6 +494,17 @@ static int CmdLFHitagURead(const char *Cmd) {
return PM3_SUCCESS;
}
// A Hitag u reports its UID and IC revision separately from its pages, so
// neither survives in the raw dump buffer. saveFileJSON's callback takes only
// the json root, so park them here for the duration of the save.
static uint8_t s_htu_uid[HITAGU_UID_SIZE] = {0};
static uint8_t s_htu_icr = 0;
static void htu_json_callback(json_t *root) {
JsonSaveBufAsHexCompact(root, "$.Card.UID", s_htu_uid, sizeof(s_htu_uid));
JsonSaveBufAsHexCompact(root, "$.Card.ICR", &s_htu_icr, sizeof(s_htu_icr));
}
static int CmdLFHitagUDump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag htu dump",
@@ -587,7 +598,9 @@ static int CmdLFHitagUDump(const char *Cmd) {
FillFileNameByUID(fptr, card->uid, "-dump", HITAGU_UID_SIZE);
}
pm3_save_dump(filename, (uint8_t *)card->pages, mem_size, jsfHitag);
memcpy(s_htu_uid, card->uid, sizeof(s_htu_uid));
s_htu_icr = card->icr;
pm3_save_dump_cb(filename, (uint8_t *)card->pages, mem_size, jsfHitagU, htu_json_callback);
return PM3_SUCCESS;
}
+73 -7
View File
@@ -29,6 +29,7 @@
#include "cmdhficlass.h" // pagemap
#include "iclass_cmd.h"
#include "iso15.h"
#include "hitag.h"
#ifdef _WIN32
#include "scandir.h"
@@ -668,15 +669,53 @@ int prepareJSON(json_t *root, JSONFileType ftype, uint8_t *data, size_t datalen,
}
break;
}
case jsfHitag: {
uint8_t uid[4] = {0};
memcpy(uid, data, 4);
JsonSaveStr(root, "FileType", "hitag");
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
// Hitag 1 and Hitag 2 both start with the UID in block 0. Hitag 2 also
// carries its configuration in block 3, so record it when the dump is
// long enough to hold one.
case jsfHitag1:
case jsfHitag2: {
JsonSaveStr(root, "FileType", (ftype == jsfHitag1) ? "hitag1" : "hitag2");
JsonSaveBufAsHexCompact(root, "$.Card.UID", data, HITAG_UID_SIZE);
for (size_t i = 0; i < (datalen / 4); i++) {
if ((ftype == jsfHitag2) && (datalen >= 16)) {
JsonSaveBufAsHexCompact(root, "$.Card.Config", data + 12, HITAG_BLOCK_SIZE);
}
JsonSaveInt(root, "$.Card.Blocks", (int)(datalen / HITAG_BLOCK_SIZE));
for (size_t i = 0; i < (datalen / HITAG_BLOCK_SIZE); i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
JsonSaveBufAsHexCompact(root, path, data + (i * HITAG_BLOCK_SIZE), HITAG_BLOCK_SIZE);
}
break;
}
// Hitag S keeps the UID in page 0 and the configuration in page 1
case jsfHitagS: {
JsonSaveStr(root, "FileType", "hitags");
JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (HITAGS_UID_PADR * HITAGS_PAGE_SIZE), HITAG_UID_SIZE);
if (datalen >= ((HITAGS_CONFIG_PADR + 1) * HITAGS_PAGE_SIZE)) {
JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (HITAGS_CONFIG_PADR * HITAGS_PAGE_SIZE), HITAGS_PAGE_SIZE);
}
JsonSaveInt(root, "$.Card.Blocks", (int)(datalen / HITAGS_PAGE_SIZE));
for (size_t i = 0; i < (datalen / HITAGS_PAGE_SIZE); i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * HITAGS_PAGE_SIZE), HITAGS_PAGE_SIZE);
}
break;
}
// Hitag u has a 6 byte UID and an ICR that the tag reports separately from
// its pages, so neither can be recovered from `data`. The caller supplies
// them through the save callback, see pm3_save_dump_cb().
case jsfHitagU: {
JsonSaveStr(root, "FileType", "hitagu");
JsonSaveInt(root, "$.Card.Blocks", (int)(datalen / HITAGU_BLOCK_SIZE));
for (size_t i = 0; i < (datalen / HITAGU_BLOCK_SIZE); i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * HITAGU_BLOCK_SIZE), HITAGU_BLOCK_SIZE);
}
break;
}
@@ -2061,7 +2100,20 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out;
}
// The four Hitag flavours share one block layout on disk and differ only in
// how many blocks they carry, so one reader serves all of them. A file
// written before the per-flavour types existed says only "hitag" and cannot
// say which tag it came from - treat those as Hitag 2 and tell the user.
if (!strcmp(ctype, "hitag")) {
PrintAndLogEx(WARNING, "`" _YELLOW_("hitag") "` is the legacy dump type and does not record which tag it came from");
PrintAndLogEx(INFO, "Reading it as " _YELLOW_("Hitag 2") ", re-dump the tag to get a versioned file");
}
if (!strcmp(ctype, "hitag") ||
!strcmp(ctype, "hitag1") ||
!strcmp(ctype, "hitag2") ||
!strcmp(ctype, "hitags") ||
!strcmp(ctype, "hitagu")) {
size_t sptr = 0;
for (int i = 0; i < (maxdatalen / 4); i++) {
if (sptr + 4 > maxdatalen) {
@@ -3929,6 +3981,20 @@ int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
return PM3_SUCCESS;
}
int pm3_save_dump_cb(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, void (*callback)(json_t *)) {
if (fn == NULL || strlen(fn) == 0) {
return PM3_EINVARG;
}
if (d == NULL || n == 0) {
PrintAndLogEx(INFO, "No data to save, skipping...");
return PM3_EINVARG;
}
saveFile(fn, ".bin", d, n);
saveFileJSON(fn, jsft, d, n, callback);
return PM3_SUCCESS;
}
int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
if (fn == NULL || d == NULL || n == 0) {
+7 -1
View File
@@ -50,7 +50,10 @@ typedef enum {
jsfMfc_v2,
jsfMfc_v3,
jsfMfuMemory,
jsfHitag,
jsfHitag1,
jsfHitag2,
jsfHitagS,
jsfHitagU,
jsfIclass,
jsf14b,
jsf14b_v2,
@@ -442,6 +445,9 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
* @return PM3_SUCCESS if OK
*/
int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
// as pm3_save_dump, but lets the caller add fields the raw dump cannot carry,
// such as the Hitag u UID and ICR which arrive separately from the pages
int pm3_save_dump_cb(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, void (*callback)(json_t *));
int pm3_save_dump_json(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
/** STUB