reworked the JSON format for 14a, 14b, 15, cryptorf, lto, NDEF.\nDeprecated EML format. Pm3 client do not save EML files any more.nPm3 client will continue to load EML files.

This commit is contained in:
iceman1001 2023-10-02 20:11:23 +02:00
commit fb23d2047f
27 changed files with 617 additions and 319 deletions

View file

@ -3,6 +3,8 @@ 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]
- Changed the json file formats for mfc, 14b, 15, legic, cryptorf, ndef (@iceman1001)
- Depricated the EML file format when saving dump files. (@iceman1001)
- Added `sim014.bin` - new sim module firmware v4.42 with improved ISO7816 Protocol T0 support (@gentilkiwi)
- Added datasheet for sim module (@iceman1001)
- Changed `smart raw --timeout` - allows for a custom timeout (@iceman1001)

View file

@ -379,8 +379,7 @@ static int CmdFlashMemDump(const char *Cmd) {
}
if (filename[0] != '\0') {
saveFile(filename, ".bin", dump, len);
saveFileEML(filename, dump, len, 16);
pm3_save_dump(filename, dump, len, jsfRaw);
}
free(dump);

View file

@ -370,14 +370,13 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
"Dumps device SPIFFS file to a local file\n"
"Size is handled by first sending a STAT command against file to verify existence",
"mem spiffs dump -s tag.bin --> download binary file from device\n"
"mem spiffs dump -s tag.bin -d aaa -e --> download tag.bin, save as aaa.eml format"
"mem spiffs dump -s tag.bin -d a001 -e --> download tag.bin, save as `a001.bin`"
);
void *argtable[] = {
arg_param_begin,
arg_str1("s", "src", "<fn>", "SPIFFS file to save"),
arg_str0("d", "dest", "<fn>", "file name to save to <w/o .bin>"),
arg_lit0("e", "eml", "also save in EML format"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -390,7 +389,6 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
char dest[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, FILE_PATH_SIZE, &dlen);
bool eml = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
// get size from spiffs itself !
@ -433,15 +431,6 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
else
saveFile(fn, ".bin", dump, len); // default
if (eml) {
uint8_t eml_len = 16;
if (strstr(fn, "class") != NULL)
eml_len = 8;
else if (strstr(fn, "mfu") != NULL)
eml_len = 4;
saveFileEML(fn, dump, len, eml_len);
}
free(dump);
return PM3_SUCCESS;
}

View file

@ -2748,6 +2748,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool verbose = arg_get_lit(ctx, 2);
bool verbose2 = arg_get_lit(ctx, 2) > 1;
CLIParserFree(ctx);
bool activate_field = true;
@ -2934,11 +2935,24 @@ int CmdHF14ANdefRead(const char *Cmd) {
memcpy(ndef_file + (i - offset), response, segment_size);
}
if (fnlen != 0) {
saveFile(filename, ".bin", ndef_file, ndef_size);
}
if (verbose2) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("NDEF raw") " ----------------");
print_buffer(ndef_file, ndef_size, 1);
}
NDEFRecordsDecodeAndPrint(ndef_file, ndef_size, verbose);
pm3_save_dump(filename, ndef_file, ndef_size, jsfNDEF);
if (verbose == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf 14a ndefread -v`") " for more details");
} else {
if (verbose2 == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf 14a ndefread -vv`") " for more details");
}
}
free(ndef_file);
return PM3_SUCCESS;
}

View file

@ -1546,7 +1546,7 @@ static int CmdHF14BDump(const char *Cmd) {
}
size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE;
pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE);
pm3_save_dump(filename, data, datalen, jsf14b_v2);
}
}
@ -2121,9 +2121,13 @@ int CmdHF14BNdefRead(const char *Cmd) {
goto out;
}
if (fnlen != 0) {
saveFile(filename, ".bin", response + 2, resplen - 4);
}
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(response + 2, resplen - 4, &n) != PM3_SUCCESS)
n = resplen - 4;
pm3_save_dump(filename, response + 2, n, jsfNDEF);
res = NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose);
out:

View file

@ -62,7 +62,7 @@
typedef struct {
uint8_t lock;
uint8_t block[4];
uint8_t block[8];
} t15memory_t;
// structure and database for uid -> tagtype lookups
@ -1143,14 +1143,14 @@ static int CmdHF15ELoad(const char *Cmd) {
static int CmdHF15ESave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 15 esave",
"Save emulator memory into three files (BIN/EML/JSON) ",
"Save emulator memory into two files (BIN/JSON) ",
"hf 15 esave -f hf-15-01020304"
"hf 15 esave -b 8 -c 42 -f hf-15-01020304"
);
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump"),
arg_int0("b", "blocksize", "<dec>", "block size, defaults to 4"),
arg_int0(NULL, "bsize", "<dec>", "block size, defaults to 4"),
arg_int0("c", "count", "<dec>", "number of blocks to export, defaults to all"),
arg_param_end
};
@ -1176,13 +1176,18 @@ static int CmdHF15ESave(const char *Cmd) {
}
PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes);
if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) {
if (GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(dump);
return PM3_ETIMEOUT;
}
pm3_save_dump(filename, dump, bytes, jsf15, blocksize);
if (blocksize == 8) {
pm3_save_dump(filename, dump, bytes, jsf15_v3);
} else {
pm3_save_dump(filename, dump, bytes, jsf15_v2);
}
free(dump);
return PM3_SUCCESS;
}
@ -1604,9 +1609,12 @@ static int CmdHF15Dump(const char *Cmd) {
// memory.
t15memory_t mem[256];
uint8_t data[256 * 4] = {0};
uint8_t data[256 * 8] = {0};
memset(data, 0, sizeof(data));
// keep track of which block length tag returned?
uint8_t blklen = 4;
for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) {
req[10] = blocknum;
@ -1646,9 +1654,15 @@ static int CmdHF15Dump(const char *Cmd) {
break;
}
// lock byte value
mem[blocknum].lock = resp.data.asBytes[0];
memcpy(mem[blocknum].block, resp.data.asBytes + 1, 4);
memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4);
// is tag responding with 4 or 8 bytes?
if (resp.length == 11) {
blklen = 8;
}
memcpy(mem[blocknum].block, resp.data.asBytes + 1, blklen);
memcpy(data + (blocknum * 4), resp.data.asBytes + 1, blklen);
retry = 0;
blocknum++;
@ -1659,6 +1673,10 @@ static int CmdHF15Dump(const char *Cmd) {
DropField();
if (blklen == 8) {
PrintAndLogEx(INFO, "8 byte block length detected");
}
PrintAndLogEx(NORMAL, "\n");
PrintAndLogEx(INFO, "block# | data |lck| ascii");
PrintAndLogEx(INFO, "---------+--------------+---+----------");
@ -1672,9 +1690,9 @@ static int CmdHF15Dump(const char *Cmd) {
PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s"
, i
, i
, sprint_hex(mem[i].block, 4)
, sprint_hex(mem[i].block, blklen)
, lck
, sprint_ascii(mem[i].block, 4)
, sprint_ascii(mem[i].block, blklen)
);
}
PrintAndLogEx(NORMAL, "");
@ -1687,8 +1705,11 @@ static int CmdHF15Dump(const char *Cmd) {
FillFileNameByUID(fptr, SwapEndian64(uid, sizeof(uid), 8), "-dump", sizeof(uid));
}
size_t datalen = blocknum * 4;
pm3_save_dump(filename, data, datalen, jsf15, 4);
if (blklen == 8) {
pm3_save_dump(filename, data, (blocknum * blklen), jsf15_v3);
} else {
pm3_save_dump(filename, data, (blocknum * blklen), jsf15_v2);
}
return PM3_SUCCESS;
}
@ -2000,15 +2021,16 @@ static int CmdHF15Readblock(const char *Cmd) {
return PM3_EWRONGANSWER;
}
// print response
char lck[16] = {0};
if (data[1]) {
snprintf(lck, sizeof(lck), _RED_("%d"), data[1]);
snprintf(lck, sizeof(lck), _RED_("%02X"), data[1]);
} else {
snprintf(lck, sizeof(lck), "%d", data[1]);
snprintf(lck, sizeof(lck), "%02X", data[1]);
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, " #%3d |lck| ascii", block);
PrintAndLogEx(INFO, "#%3d |lck| ascii", block);
PrintAndLogEx(INFO, "------------+---+------");
PrintAndLogEx(INFO, "%s| %s | %s", sprint_hex(data + 2, resp.length - 4), lck, sprint_ascii(data + 2, resp.length - 4));
PrintAndLogEx(NORMAL, "");
@ -2834,7 +2856,7 @@ static int CmdHF15View(const char *Cmd) {
);
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"),
arg_str1("f", "file", "<fn>", "filename of dump"),
// arg_lit0("z", "dense", "dense dump output style"),
arg_param_end
};

View file

@ -414,9 +414,8 @@ static int CmdHFCryptoRFDump(const char *Cmd) {
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
}
saveFileEML(filename, data, datalen, 4);
saveFile(filename, ".bin", data, datalen);
// json?
pm3_save_dump(filename, data, datalen, jsfCryptorf);
return switch_off_field_cryptorf();
}
@ -486,14 +485,14 @@ static int CmdHFCryptoRFESave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cryptorf esave",
"Save emulator memory to bin/eml/json file\n"
"Save emulator memory to to two files (bin/json)\n"
"if filename is not supplied, UID will be used.",
"hf cryptorf esave\n"
"hf cryptorf esave -f filename"
);
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dumpfile"),
arg_str0("f", "file", "<fn>", "filename of dump"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -527,11 +526,7 @@ static int CmdHFCryptoRFESave(const char *Cmd) {
FillFileNameByUID(fptr, data, "-dump", 4);
}
saveFile(filename, ".bin", data, numofbytes);
//needs to change
saveFileEML(filename, data, numofbytes, 8);
//needs to change
saveFileJSON(filename, jsfRaw, data, numofbytes, NULL);
pm3_save_dump(filename, data, numofbytes, jsfCryptorf);
free(data);
return PM3_SUCCESS;
}

View file

@ -339,14 +339,7 @@ static int CmdHFFudanDump(const char *Cmd) {
free(fptr);
}
saveFile(dataFilename, ".bin", (uint8_t *)carddata, sizeof(carddata));
saveFileEML(dataFilename, (uint8_t *)carddata, sizeof(carddata), MAX_FUDAN_BLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = (uint8_t *)carddata;
xdump.dumplen = sizeof(carddata);
saveFileJSON(dataFilename, jsfFudan, (uint8_t *)&xdump, sizeof(xdump), NULL);
pm3_save_dump(dataFilename, (uint8_t *)carddata, sizeof(carddata), jsfFudan);
return PM3_SUCCESS;
}

View file

@ -19,8 +19,8 @@
#include "cmdhficlass.h"
#include <ctype.h>
#include "cliparser.h"
#include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN
#include "cmdtrace.h"
#include "util_posix.h"
#include "comms.h"
@ -34,13 +34,13 @@
#include "cardhelper.h"
#include "wiegand_formats.h"
#include "wiegand_formatutils.h"
#include "cmdsmartcard.h" // smart select fct
#include "cmdsmartcard.h" // smart select fct
#include "proxendian.h"
#include "iclass_cmd.h"
#include "crypto/asn1utils.h" // ASN1 decoder
#include "crypto/asn1utils.h" // ASN1 decoder
#include "preferences.h"
#define PICOPASS_BLOCK_SIZE 8
#define NUM_CSNS 9
#define MAC_ITEM_SIZE 24 // csn(8) + epurse(8) + nr(4) + mac(4) = 24 bytes
#define ICLASS_KEYS_MAX 8
@ -1016,7 +1016,7 @@ static int CmdHFiClassELoad(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"),
arg_str1("f", "file", "<fn>", "filename of dump"),
arg_lit0("m", "mem", "use RDV4 spiffs"),
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
@ -1149,7 +1149,7 @@ static int CmdHFiClassESave(const char *Cmd) {
FillFileNameByUID(fptr, dump, "-dump", 8);
}
pm3_save_dump(filename, dump, bytes, jsfIclass, PICOPASS_BLOCK_SIZE);
pm3_save_dump(filename, dump, bytes, jsfIclass);
free(dump);
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
@ -1497,7 +1497,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
strcat(fptr, "hf-iclass-");
FillFileNameByUID(fptr, hdr->csn, "-dump-decrypted", sizeof(hdr->csn));
pm3_save_dump(fptr, decrypted, decryptedlen, jsfIclass, PICOPASS_BLOCK_SIZE);
pm3_save_dump(fptr, decrypted, decryptedlen, jsfIclass);
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen, dense_output);
@ -2045,7 +2045,7 @@ write_dump:
// save the dump to .bin file
PrintAndLogEx(SUCCESS, "saving dump file - %u blocks read", bytes_got / 8);
pm3_save_dump(filename, tag_data, bytes_got, jsfIclass, PICOPASS_BLOCK_SIZE);
pm3_save_dump(filename, tag_data, bytes_got, jsfIclass);
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt -f") "` to decrypt dump file");
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
@ -3026,7 +3026,7 @@ static int CmdHFiClassView(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"),
arg_str1("f", "file", "<fn>", "filename of dump"),
arg_int0(NULL, "first", "<dec>", "Begin printing from this block (default first user block)"),
arg_int0(NULL, "last", "<dec>", "End printing at this block (default 0, ALL)"),
arg_lit0("v", "verbose", "verbose output"),

View file

@ -858,7 +858,7 @@ static int CmdLegicReader(const char *Cmd) {
static int CmdLegicDump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic dump",
"Read all memory from LEGIC Prime tags and saves to (bin/eml/json) dump file\n"
"Read all memory from LEGIC Prime tags and saves to (bin/json) dump file\n"
"It autodetects card type (MIM22, MIM256, MIM1024)",
"hf legic dump --> use UID as filename\n"
"hf legic dump -f myfile \n"
@ -951,7 +951,7 @@ static int CmdLegicDump(const char *Cmd) {
FillFileNameByUID(filename, data, "-dump", 4);
}
pm3_save_dump(filename, data, readlen, jsfLegic, LEGIC_BLOCK_SIZE);
pm3_save_dump(filename, data, readlen, jsfLegic_v2);
free(data);
return PM3_SUCCESS;
}
@ -1119,7 +1119,7 @@ static int CmdLegicELoad(const char *Cmd) {
static int CmdLegicESave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic esave",
"Saves a (bin/eml/json) dump file of emulator memory",
"Saves a (bin/json) dump file of emulator memory",
"hf legic esave --> uses UID as filename\n"
"hf legic esave -f myfile --22\n"
"hf legic esave -f myfile --22 --de\n"
@ -1188,7 +1188,7 @@ static int CmdLegicESave(const char *Cmd) {
legic_xor(data, numofbytes);
}
pm3_save_dump(filename, data, numofbytes, jsfLegic, LEGIC_BLOCK_SIZE);
pm3_save_dump(filename, data, numofbytes, jsfLegic_v2);
return PM3_SUCCESS;
}

View file

@ -771,8 +771,7 @@ static int CmdHfLTODump(const char *Cmd) {
char *fptr = filename + snprintf(filename, sizeof(filename), "hf-lto-");
FillFileNameByUID(fptr, dump, "-dump", 5);
}
saveFile(filename, ".bin", dump, dump_len);
saveFileEML(filename, dump, dump_len, 32);
pm3_save_dump(filename, dump, dump_len, jsfLto);
free(dump);
return PM3_SUCCESS;
}

View file

@ -472,7 +472,7 @@ void mf_print_sector_hdr(uint8_t sector) {
static bool mf_write_block(const uint8_t *key, uint8_t keytype, uint8_t blockno, uint8_t *block) {
uint8_t data[26];
memcpy(data, key, MFKEY_SIZE);
memcpy(data, key, MIFARE_KEY_SIZE);
memcpy(data + 10, block, MFBLOCK_SIZE);
clearCommandBuffer();
@ -1230,14 +1230,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
free(fptr);
}
saveFile(dataFilename, ".bin", mem, bytes);
saveFileEML(dataFilename, mem, bytes, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = mem;
xdump.dumplen = bytes;
saveFileJSON(dataFilename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
pm3_save_mf_dump(dataFilename, mem, bytes, jsfCardMemory);
free(mem);
return PM3_SUCCESS;
}
@ -3164,13 +3157,7 @@ all_found:
strncpy(filename, fptr, sizeof(filename) - 1);
free(fptr);
saveFile(filename, ".bin", dump, bytes);
saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = dump;
xdump.dumplen = bytes;
saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory);
// Generate and show statistics
t1 = msclock() - t1;
@ -4452,7 +4439,7 @@ static int CmdHF14AMfESave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf esave",
"Save emulator memory into three files (BIN/EML/JSON) ",
"Save emulator memory into two files (bin//json) ",
"hf mf esave\n"
"hf mf esave --4k\n"
"hf mf esave --4k -f hf-mf-01020304.eml"
@ -4522,30 +4509,7 @@ static int CmdHF14AMfESave(const char *Cmd) {
FillFileNameByUID(fptr, dump, "-dump", 4);
}
saveFile(filename, ".bin", dump, bytes);
saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump = {0};
xdump.card_info.ats_len = 0;
// Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA
if ((dump[0] ^ dump[1] ^ dump[2] ^ dump[3]) == dump[4] && (dump[6] & 0xc0) == 0) {
xdump.card_info.uidlen = 4;
memcpy(xdump.card_info.uid, dump, xdump.card_info.uidlen);
xdump.card_info.sak = dump[5];
memcpy(xdump.card_info.atqa, &dump[6], sizeof(xdump.card_info.atqa));
}
// Check for 7 bytes UID: double size uid bits in ATQA
else if ((dump[8] & 0xc0) == 0x40) {
xdump.card_info.uidlen = 7;
memcpy(xdump.card_info.uid, dump, xdump.card_info.uidlen);
xdump.card_info.sak = dump[7];
memcpy(xdump.card_info.atqa, &dump[8], sizeof(xdump.card_info.atqa));
} else {
PrintAndLogEx(WARNING, "Invalid dump. UID/SAK/ATQA not found");
}
xdump.dump = dump;
xdump.dumplen = bytes;
saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory);
free(dump);
return PM3_SUCCESS;
}
@ -5217,7 +5181,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) {
static int CmdHF14AMfCSave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf csave",
"Save magic gen1a card memory into three files (BIN/EML/JSON)"
"Save magic gen1a card memory into two files (bin/json)"
"or into emulator memory",
"hf mf csave\n"
"hf mf csave --4k"
@ -5364,13 +5328,7 @@ static int CmdHF14AMfCSave(const char *Cmd) {
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
}
saveFile(filename, ".bin", dump, bytes);
saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = dump;
xdump.dumplen = bytes;
saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory);
free(dump);
return PM3_SUCCESS;
}
@ -6176,16 +6134,19 @@ int CmdHFMFNDEFRead(const char *Cmd) {
print_buffer(data, datalen, 1);
}
if (fnlen != 0) {
saveFile(filename, ".bin", data, datalen);
}
res = NDEFDecodeAndPrint(data, datalen, verbose);
if (res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header");
res = NDEFRecordsDecodeAndPrint(data, datalen, verbose);
}
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(data, datalen, &n) != PM3_SUCCESS)
n = datalen;
pm3_save_dump(filename, data, n, jsfNDEF);
if (verbose == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mf ndefread -v`") " for more details");
} else {
@ -6282,8 +6243,8 @@ int CmdHFMFNDEFFormat(const char *Cmd) {
// init keys to default key
uint8_t keyA[MIFARE_4K_MAXSECTOR][MFKEY_SIZE];
uint8_t keyB[MIFARE_4K_MAXSECTOR][MFKEY_SIZE];
uint8_t keyA[MIFARE_4K_MAXSECTOR][MIFARE_KEY_SIZE];
uint8_t keyB[MIFARE_4K_MAXSECTOR][MIFARE_KEY_SIZE];
for (uint8_t i = 0; i < MIFARE_4K_MAXSECTOR; i++) {
memcpy(keyA[i], g_mifare_default_key, sizeof(g_mifare_default_key));
@ -6314,7 +6275,6 @@ int CmdHFMFNDEFFormat(const char *Cmd) {
DropField();
}
// load key file if exist
if (strlen(keyFilename)) {
//
@ -7402,7 +7362,6 @@ static int CmdHF14AMfView(const char *Cmd) {
block_cnt = MIFARE_4K_MAXBLOCK;
if (verbose) {
PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt);
}
@ -7896,7 +7855,7 @@ static int CmdHF14AGen4Save(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gsave",
"Save `magic gen4 gtu` card memory into three files (BIN/EML/JSON)"
"Save `magic gen4 gtu` card memory into two files (bin/json)"
"or into emulator memory",
"hf mf gsave\n"
"hf mf gsave --4k\n"
@ -7908,7 +7867,7 @@ static int CmdHF14AGen4Save(const char *Cmd) {
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
arg_str0("p", "pwd", "<hex>", "password 4bytes"),
arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
arg_str0("f", "file", "<fn>", "filename of dump"),
arg_lit0(NULL, "emu", "to emulator memory"),
arg_param_end
@ -8079,14 +8038,7 @@ static int CmdHF14AGen4Save(const char *Cmd) {
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
}
saveFile(filename, ".bin", dump, bytes);
saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = dump;
xdump.dumplen = bytes;
saveFileJSON(filename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
pm3_save_mf_dump(filename, dump, bytes, jsfCardMemory);
free(dump);
return PM3_SUCCESS;
}

View file

@ -1126,9 +1126,9 @@ static int CmdHF14aDesChk(const char *Cmd) {
CLIParserInit(&ctx, "hf mfdes chk",
"Checks keys with MIFARE DESFire card.",
"hf mfdes chk --aid 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n"
"hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card\n"
"hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys from dictionary against aid 0x123456\n"
"hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to json\n"
"hf mfdes chk -d mfdes_default_keys -> check keys against all existing aid on card\n"
"hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys against aid 0x123456\n"
"hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to `keys.json`\n"
"hf mfdes chk --aid 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00");
void *argtable[] = {

View file

@ -1448,14 +1448,7 @@ static int CmdHFMFPDump(const char *Cmd) {
free(fptr);
}
saveFile(data_fn, ".bin", mem, MIFARE_4K_MAX_BYTES);
saveFileEML(data_fn, mem, MIFARE_4K_MAX_BYTES, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = mem;
xdump.dumplen = MIFARE_4K_MAX_BYTES;
saveFileJSON(data_fn, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
pm3_save_mf_dump(filename, dump, MIFARE_4K_MAX_BYTES, jsfCardMemory);
*/
free(mem);
return PM3_SUCCESS;
@ -1746,16 +1739,19 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
print_buffer(data, datalen, 1);
}
if (fnlen != 0) {
saveFile(filename, ".bin", data, datalen);
}
res = NDEFDecodeAndPrint(data, datalen, verbose);
if (res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header");
res = NDEFRecordsDecodeAndPrint(data, datalen, verbose);
}
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(data, datalen, &n) != PM3_SUCCESS)
n = datalen;
pm3_save_dump(filename, data, n, jsfNDEF);
if (verbose == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -v`") " for more details");
} else {

View file

@ -2677,7 +2677,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
}
uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory, MFU_BLOCK_SIZE);
pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory);
if (is_partial) {
PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size);
@ -2840,7 +2840,7 @@ int CmdHF14MfUTamper(const char *Cmd) {
static int CmdHF14AMfURestore(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu restore",
"Restore MIFARE Ultralight/NTAG dump file to tag.\n",
"Restore MIFARE Ultralight/NTAG dump file (bin/eml/json) to tag.\n",
"hf mfu restore -f myfile -s -> special write\n"
"hf mfu restore -f myfile -k AABBCCDD -s -> special write, use key\n"
"hf mfu restore -f myfile -k AABBCCDD -ser -> special write, use key, write dump pwd, ..."
@ -2848,7 +2848,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "specify dump filename (bin/eml/json)"),
arg_str1("f", "file", "<fn>", "specify dump filename"),
arg_str0("k", "key", "<hex>", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
arg_lit0("l", NULL, "swap entered key's endianness"),
arg_lit0("s", NULL, "enable special write UID -MAGIC TAG ONLY-"),
@ -4443,14 +4443,20 @@ int CmdHF14MfuNDEFRead(const char *Cmd) {
}
DropField();
if (fnlen != 0) {
saveFile(filename, ".bin", records, (size_t)maxsize);
}
status = NDEFRecordsDecodeAndPrint(records, (size_t)maxsize, verbose);
if (status != PM3_SUCCESS) {
status = NDEFDecodeAndPrint(records, (size_t)maxsize, verbose);
}
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(records, maxsize, &n) != PM3_SUCCESS)
n = maxsize;
pm3_save_dump(filename, records, n, jsfNDEF);
char *jooki = strstr((char *)records, "s.jooki.rocks/s/?s=");
if (jooki) {
jooki += 17;
@ -4557,12 +4563,12 @@ static int CmdHF14AMfuEView(const char *Cmd) {
static int CmdHF14AMfuESave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu esave",
"Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json)\n"
"Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/json)\n"
"By default number of pages saved depends on defined tag type.\n"
"You can override this with option --end.",
"hf mfu esave\n"
"hf mfu esave --end 255 -> saves whole memory\n"
"hf mfu esave -f hf-mfu-04010203040506-dump.json"
"hf mfu esave -f hf-mfu-04010203040506-dump"
);
void *argtable[] = {
@ -4613,7 +4619,7 @@ static int CmdHF14AMfuESave(const char *Cmd) {
// save dump. Last block contains PACK + RFU
uint16_t datalen = (end + 1) * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
res = pm3_save_dump(filename, (uint8_t *)dump, datalen, jsfMfuMemory, MFU_BLOCK_SIZE);
res = pm3_save_dump(filename, (uint8_t *)dump, datalen, jsfMfuMemory);
free(dump);
return res;

View file

@ -404,10 +404,15 @@ int CmdHFST25TANdefRead(const char *Cmd) {
return PM3_ESOFT;
}
if (fnlen != 0) {
saveFile(filename, ".bin", response + 2, resplen - 4);
}
NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose);
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(response, resplen, &n) != PM3_SUCCESS)
n = resplen;
pm3_save_dump(filename, response + 2, n, jsfNDEF);
return PM3_SUCCESS;
}

View file

@ -897,9 +897,9 @@ static int CmdHFTopazDump(const char *Cmd) {
}
if (topaz_tag.size)
pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t) + topaz_tag.size, jsfTopaz, TOPAZ_BLOCK_SIZE);
pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t) + topaz_tag.size, jsfTopaz);
else
pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t), jsfTopaz, TOPAZ_BLOCK_SIZE);
pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t), jsfTopaz);
if (set_dynamic) {
free(topaz_tag.dynamic_memory);
@ -916,7 +916,7 @@ static int CmdHFTopazView(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"),
arg_str1("f", "file", "<fn>", "filename of dump"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -611,9 +611,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool decrypt = arg_get_lit(ctx, 2);
CLIParserFree(ctx);
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11);
@ -682,7 +680,6 @@ static int CmdHFXeroxDump(const char *Cmd) {
PrintAndLogEx(NORMAL, "." NOLF);
fflush(stdout);
// PrintAndLogEx(INPLACE, "blk %3d", blocknum);
}
}
@ -773,23 +770,13 @@ static int CmdHFXeroxDump(const char *Cmd) {
PrintAndLogEx(NORMAL, "");
if (0 == filename[0]) { // generate filename from uid
/*
PrintAndLogEx(INFO, "Using UID as filename");
sprintf(filename, "hf-xerox-%02X%02X%02X%02X%02X%02X%02X%02X-dump%s",
card.uid[7],card.uid[6],card.uid[5],card.uid[4],card.uid[3],card.uid[2],card.uid[1],card.uid[0],
decrypt ? "-dec" : "");
*/
char *fptr = filename;
PrintAndLogEx(INFO, "Using UID as filename");
fptr += snprintf(fptr, sizeof(filename), "hf-xerox-");
FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), decrypt ? "-dump-dec" : "-dump", card.uidlen);
}
size_t datalen = blocknum * 4;
saveFile(filename, ".bin", data, datalen);
saveFileEML(filename, data, datalen, 4);
// saveFileJSON(filename, jsf15, data, datalen, NULL);
pm3_save_dump(filename, data, blocknum * 4, jsf14b_v2);
return PM3_SUCCESS;
}

View file

@ -709,9 +709,9 @@ int CmdEM4x05Dump(const char *Cmd) {
}
PrintAndLogEx(NORMAL, "");
if (card_type == EM_4369 || card_type == EM_4469)
pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x69, 4);
pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x69);
else
pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x05, 4);
pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x05);
}
PrintAndLogEx(NORMAL, "");
return success;

View file

@ -194,7 +194,7 @@ int CmdEM4x50ELoad(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "dump filename (bin/eml/json)"),
arg_str1("f", "file", "<fn>", "dump filename"),
arg_param_end
};
@ -223,7 +223,7 @@ int CmdEM4x50ELoad(const char *Cmd) {
int CmdEM4x50ESave(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 esave",
"Saves bin/eml/json dump file of emulator memory.",
"Saves bin/json dump file of emulator memory.",
"lf em 4x50 esave -> use UID as filename\n"
"lf em 4x50 esave -f mydump\n"
);
@ -264,7 +264,7 @@ int CmdEM4x50ESave(const char *Cmd) {
FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4);
}
pm3_save_dump(filename, data, DUMP_FILESIZE, jsfEM4x50, 4);
pm3_save_dump(filename, data, DUMP_FILESIZE, jsfEM4x50);
return PM3_SUCCESS;
}
@ -796,7 +796,7 @@ int CmdEM4x50Reader(const char *Cmd) {
int CmdEM4x50Dump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 dump",
"Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format",
"Reads all blocks/words from EM4x50 tag and saves dump in (bin/json) format",
"lf em 4x50 dump\n"
"lf em 4x50 dump -f mydump\n"
"lf em 4x50 dump -p 12345678\n"
@ -805,7 +805,7 @@ int CmdEM4x50Dump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<fn>", "specify dump filename (bin/eml/json)"),
arg_str0("f", "file", "<fn>", "specify dump filename"),
arg_str0("p", "pwd", "<hex>", "password, 4 hex bytes, lsb"),
arg_param_end
};
@ -867,7 +867,7 @@ int CmdEM4x50Dump(const char *Cmd) {
memcpy(data + (i * 4), words[i].byte, 4);
}
pm3_save_dump(filename, data, sizeof(data), jsfEM4x50, 4);
pm3_save_dump(filename, data, sizeof(data), jsfEM4x50);
return PM3_SUCCESS;
}

View file

@ -1127,7 +1127,7 @@ static int CmdLFHitag2Dump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
pm3_save_dump(filename, data, 48, jsfHitag, 4);
pm3_save_dump(filename, data, 48, jsfHitag);
return PM3_SUCCESS;
}

View file

@ -2217,7 +2217,7 @@ static int CmdT55xxDump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf t55xx dump",
"This command dumps a T55xx card Page 0 block 0-7.\n"
"It will create three files (bin/eml/json)",
"It will create two files (bin/json)",
"lf t55xx dump\n"
"lf t55xx dump -p aabbccdd --override\n"
"lf t55xx dump -f my_lf_dump"
@ -2315,17 +2315,13 @@ static int CmdT55xxDump(const char *Cmd) {
}
// Swap endian so the files match the txt display
uint32_t data[T55x7_BLOCK_COUNT];
uint32_t data[T55x7_BLOCK_COUNT] = {0};
for (int i = 0; i < T55x7_BLOCK_COUNT; i++) {
data[i] = BSWAP_32(cardmem[i].blockdata);
}
// saveFileEML will add .eml extension to filename
// saveFile (binary) passes in the .bin extension.
saveFileJSON(filename, jsfT55x7, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), NULL);
saveFileEML(filename, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), sizeof(uint32_t));
saveFile(filename, ".bin", data, sizeof(data));
pm3_save_dump(filename, (uint8_t*)data, (T55x7_BLOCK_COUNT * sizeof(uint32_t)), jsfT55x7);
}
return PM3_SUCCESS;

View file

@ -27,9 +27,7 @@
#include "proxmark3.h"
#include "util.h"
#include "cmdhficlass.h" // pagemap
#include "protocols.h" // iclass defines
#include "cmdhftopaz.h" // TOPAZ defines
#include "mifare/mifaredefault.h" // MFP / AES defines
#include "iclass_cmd.h"
#ifdef _WIN32
#include "scandir.h"
@ -329,12 +327,8 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
}
}
char *fileName = newfilenamemcopyEx(preferredName, ".json", e_save_path);
if (fileName == NULL) {
return PM3_EMALLOC;
}
int retval = PM3_SUCCESS;
char path[PATH_MAX_LENGTH] = {0};
json_t *root = json_object();
JsonSaveStr(root, "Created", "proxmark3");
@ -344,26 +338,26 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
break;
}
case jsfCardMemory: {
case jsfMfc_v2: {
iso14a_mf_extdump_t *xdump = (iso14a_mf_extdump_t *)(void *) data;
JsonSaveStr(root, "FileType", "mfcard");
JsonSaveStr(root, "FileType", "mfc v2");
JsonSaveBufAsHexCompact(root, "$.Card.UID", xdump->card_info.uid, xdump->card_info.uidlen);
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump->card_info.atqa, 2);
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump->card_info.sak), 1);
for (size_t i = 0; i < (xdump->dumplen / 16); i++) {
char path[PATH_MAX_LENGTH] = {0};
for (size_t i = 0; i < (xdump->dumplen / MFBLOCK_SIZE); i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16], 16);
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE], MFBLOCK_SIZE);
if (mfIsSectorTrailer(i)) {
snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyA", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16], 6);
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE], 6);
snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyB", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16 + 10], 6);
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE + 10], 6);
uint8_t *adata = &xdump->dump[i * 16 + 6];
uint8_t *adata = &xdump->dump[i * MFBLOCK_SIZE + 6];
snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditions", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 16 + 6], 4);
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * MFBLOCK_SIZE + 6], 4);
snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 3);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata));
@ -390,7 +384,7 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump->card_info.atqa, 2);
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump->card_info.sak), 1);
for (size_t i = 0; i < (xdump->dumplen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 4], 4);
}
@ -405,8 +399,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
memcpy(uid, tmp->data, 3);
memcpy(uid + 3, tmp->data + 4, 4);
char path[PATH_MAX_LENGTH] = {0};
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
@ -420,11 +412,12 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
}
// size of header 56b
size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / 4;
size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / MFU_BLOCK_SIZE;
for (size_t i = 0; i < len; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, tmp->data + (i * 4), 4);
JsonSaveBufAsHexCompact(root, path, tmp->data + (i * MFU_BLOCK_SIZE), MFU_BLOCK_SIZE);
}
break;
}
@ -436,7 +429,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
@ -460,10 +452,10 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.AIA", hdr->app_issuer_area, sizeof(hdr->app_issuer_area));
}
for (size_t i = 0; i < (datalen / 8); i++) {
char path[PATH_MAX_LENGTH] = {0};
for (size_t i = 0; i < (datalen / PICOPASS_BLOCK_SIZE); i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 8), 8);
JsonSaveBufAsHexCompact(root, path, data + (i * PICOPASS_BLOCK_SIZE), PICOPASS_BLOCK_SIZE);
}
break;
@ -475,25 +467,49 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
break;
}
case jsf14b: {
JsonSaveStr(root, "FileType", "14b");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
case jsf14b_v2: {
JsonSaveStr(root, "FileType", "14b v2");
for (size_t i = 0; i < datalen / 4; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 4], 4);
}
break;
}
case jsf15: {
JsonSaveStr(root, "FileType", "15693");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
// handles ISO15693 w blocksize of 4 bytes
case jsf15_v2: {
JsonSaveStr(root, "FileType", "15693 v2");
for (size_t i = 0; i < datalen / 4; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 4], 4);
}
break;
}
case jsfLegic: {
JsonSaveStr(root, "FileType", "legic");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
// handles ISO15693 w blocksize of 8 bytes
case jsf15_v3: {
JsonSaveStr(root, "FileType", "15693 v3");
for (size_t i = 0; i < datalen / 8; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 8], 8);
}
break;
}
case jsfLegic_v2: {
JsonSaveStr(root, "FileType", "legic v2");
JsonSaveBufAsHexCompact(root, "$.Card.UID", data, 4);
size_t i = 0;
for (; i < datalen / 16; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
}
if (datalen % 16) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 16], (datalen % 16));
}
break;
}
case jsfT5555: {
@ -503,7 +519,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
@ -517,7 +532,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.Protection2", data + (15 * 4), 4);
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
@ -530,7 +544,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4);
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
@ -544,7 +557,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (33 * 4), 4);
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
@ -564,8 +576,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
memcpy(vdata, data + (14 + atslen), 2 * 64 * 17);
for (size_t i = 0; i < datalen; i++) {
char path[PATH_MAX_LENGTH] = {0};
if (vdata[0][i][0]) {
snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyA", i);
JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], AES_KEY_LEN);
@ -591,31 +601,27 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
memcpy(dvdata, &data[14 + datslen], 4 * 0xE * (24 + 1));
for (int i = 0; i < (int)datalen; i++) {
char path[PATH_MAX_LENGTH] = {0};
if (dvdata[0][i][0]) {
snprintf(path, sizeof(path), "$.DES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], 8);
JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], DES_KEY_LEN);
}
if (dvdata[1][i][0]) {
snprintf(path, sizeof(path), "$.3DES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], 16);
JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], T2DES_KEY_LEN);
}
if (dvdata[2][i][0]) {
snprintf(path, sizeof(path), "$.AES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], 16);
JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], AES_KEY_LEN);
}
if (dvdata[3][i][0]) {
snprintf(path, sizeof(path), "$.K3KDES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], 24);
JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], T3DES_KEY_LEN);
}
}
break;
}
case jsfFido: {
break;
}
case jsfCustom: {
(*callback)(root);
break;
@ -626,8 +632,8 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
JsonSaveBufAsHexCompact(root, "$.Card.UID", tag->uid, sizeof(tag->uid));
JsonSaveBufAsHexCompact(root, "$.Card.H0R1", tag->HR01, sizeof(tag->HR01));
JsonSaveBufAsHexCompact(root, "$.Card.Size", (uint8_t *) & (tag->size), 2);
for (size_t i = 0; i < TOPAZ_STATIC_MEMORY / 8; i++) {
char path[PATH_MAX_LENGTH] = {0};
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &tag->data_blocks[i][0], TOPAZ_BLOCK_SIZE);
}
@ -638,24 +644,67 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
break;
}
case jsfLto: {
JsonSaveStr(root, "FileType", "lto");
for (size_t i = 0; i < datalen / 32; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 32], 32);
}
break;
}
case jsfCryptorf: {
JsonSaveStr(root, "FileType", "cryptorf");
for (size_t i = 0; i < datalen / 8; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 8], 8);
}
break;
}
case jsfNDEF: {
JsonSaveStr(root, "FileType", "ndef");
JsonSaveInt(root, "Ndef.Size", datalen);
size_t i = 0;
for (; i < datalen / 16; i++) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
}
if (datalen % 16) {
snprintf(path, sizeof(path), "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 16], (datalen % 16));
}
break;
}
// no action
case jsfFido:
break;
// depricated
case jsfCardMemory:
case jsf14b:
case jsf15:
case jsfLegic:
default:
break;
}
int res = json_dump_file(root, fileName, JSON_INDENT(2));
if (res) {
PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fileName);
char *fn = newfilenamemcopyEx(preferredName, ".json", e_save_path);
if (fn == NULL) {
return PM3_EMALLOC;
}
if (json_dump_file(root, fn, JSON_INDENT(2))) {
PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fn);
retval = 200;
free(fn);
goto out;
}
if (verbose) {
PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fileName);
PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fn);
}
free(fn);
out:
json_decref(root);
free(fileName);
return retval;
}
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose) {
@ -1083,56 +1132,56 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out;
}
typedef union UDATA {
void *v;
uint8_t *bytes;
mfu_dump_t *mfu;
topaz_tag_t *topaz;
} UDATA;
UDATA udata = (UDATA)data;
char ctype[100] = {0};
JsonLoadStr(root, "$.FileType", ctype);
if (!strcmp(ctype, "raw")) {
JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
// Proxmark3 settings file. No
if (!strcmp(ctype, "settings")) {
goto out;
}
if (!strcmp(ctype, "mfcard")) {
udata_t udata = (udata_t)data;
size_t len = 0;
char blocks[PATH_MAX_LENGTH] = {0};
if (!strcmp(ctype, "raw")) {
JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
goto out;
}
// depricated mfcard
if (!strcmp(ctype, "mfcard") || !strcmp(ctype, "mfc v2")) {
size_t sptr = 0;
for (int i = 0; i < 256; i++) {
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
for (int i = 0; i < maxdatalen; i++) {
size_t len = 0;
uint8_t block[16];
JsonLoadBufAsHex(root, blocks, block, 16, &len);
if (!len)
break;
if (sptr + 16 > maxdatalen) {
if (sptr + MFBLOCK_SIZE > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
memcpy(&udata.bytes[sptr], block, 16);
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
uint8_t block[MFBLOCK_SIZE];
JsonLoadBufAsHex(root, blocks, block, MFBLOCK_SIZE, &len);
if (!len)
break;
memcpy(&udata.bytes[sptr], block, MFBLOCK_SIZE);
sptr += len;
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "fudan")) {
size_t sptr = 0;
for (int i = 0; i < 256; i++) {
for (int i = 0; i < maxdatalen; i++) {
if (sptr + 4 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len)
break;
@ -1141,6 +1190,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "mfu")) {
@ -1164,10 +1214,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out;
}
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata.mfu->data[sptr], MFU_BLOCK_SIZE, &len);
if (!len)
break;
@ -1179,6 +1226,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
--udata.mfu->pages;
*datalen += sptr;
goto out;
}
if (!strcmp(ctype, "hitag")) {
@ -1189,10 +1237,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out;
}
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len)
break;
@ -1201,27 +1246,26 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "iclass")) {
size_t sptr = 0;
for (size_t i = 0; i < (maxdatalen / 8); i++) {
if (sptr + 8 > maxdatalen) {
for (size_t i = 0; i < (maxdatalen / PICOPASS_BLOCK_SIZE); i++) {
if (sptr + PICOPASS_BLOCK_SIZE > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], PICOPASS_BLOCK_SIZE, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "t55x7")) {
@ -1232,10 +1276,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out;
}
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len)
break;
@ -1243,6 +1284,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
sptr += len;
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "EM4X50")) {
@ -1253,10 +1295,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out;
}
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%zu", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len)
break;
@ -1264,14 +1303,80 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
sptr += len;
}
*datalen = sptr;
goto out;
}
// depricated
if (!strcmp(ctype, "15693")) {
JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
goto out;
}
// handles ISO15693 w blocksize of 4 bytes.
if (!strcmp(ctype, "15693 v2")) {
size_t sptr = 0;
for (int i = 0; i < (maxdatalen / 4); i++) {
if (sptr + 4 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
// handles ISO15693 w blocksize of 8 bytes.
if (!strcmp(ctype, "15693 v3")) {
size_t sptr = 0;
for (int i = 0; i < (maxdatalen / 8); i++) {
if (sptr + 8 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "legic v2")) {
size_t sptr = 0;
for (int i = 0; i < 64; i++) {
if (sptr + 16 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 16, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
// depricated
if (!strcmp(ctype, "legic")) {
JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
goto out;
}
if (!strcmp(ctype, "topaz")) {
@ -1288,22 +1393,19 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
goto out;
}
char blocks[30] = {0};
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata.topaz->data_blocks[sptr][0], TOPAZ_BLOCK_SIZE, &len);
if (!len)
break;
sptr += len;
// ICEMAN todo: add dynamic memory.
// uint16_z Size
// uint8_t *dynamic_memory;
}
*datalen += sptr;
goto out;
}
if (!strcmp(ctype, "mfpkeys")) {
@ -1327,7 +1429,6 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
size_t offset = (14 + atslen) + (i * 2 * AES_KEY_LEN);
char blocks[40] = {0};
snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyA", i);
JsonLoadBufAsHex(root, blocks, udata.bytes + offset, AES_KEY_LEN, datalen);
@ -1337,8 +1438,143 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
sptr += (2 * AES_KEY_LEN);
}
*datalen += sptr;
goto out;
}
if (!strcmp(ctype, "mfdes")) {
JsonLoadBufAsHex(root, "$.Card.UID", udata.bytes, 7, datalen);
JsonLoadBufAsHex(root, "$.Card.SAK", udata.bytes + 10, 1, datalen);
JsonLoadBufAsHex(root, "$.Card.ATQA", udata.bytes + 11, 2, datalen);
uint8_t atslen = udata.bytes[13];
if (atslen > 0) {
JsonLoadBufAsHex(root, "$.Card.ATS", udata.bytes + 14, atslen, datalen);
}
// size_t sptr = (14 + atslen);
// uint8_t dvdata[4][0xE][24 + 1] = {{{0}}};
/*
for (int i = 0; i < (int)datalen; i++) {
char path[PATH_MAX_LENGTH] = {0};
if (dvdata[0][i][0]) {
snprintf(path, sizeof(path), "$.DES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], DES_KEY_LEN);
}
if (dvdata[1][i][0]) {
snprintf(path, sizeof(path), "$.3DES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], T2DES_KEY_LEN);
}
if (dvdata[2][i][0]) {
snprintf(path, sizeof(path), "$.AES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], AES_KEY_LEN);
}
if (dvdata[3][i][0]) {
snprintf(path, sizeof(path), "$.K3KDES.%d.Key", i);
JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], T3DES_KEY_LEN);
}
}
*/
// memcpy(&data[14 + atslen], dvdata, 4 * 0xE * (24 + 1));
goto out;
}
if (!strcmp(ctype, "14b v2")) {
size_t sptr = 0;
for (int i = 0; i < (maxdatalen / 4); i++) {
if (sptr + 4 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "lto")) {
size_t sptr = 0;
for (int i = 0; i < (maxdatalen / 32); i++) {
if (sptr + 32 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 32, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "cryptorf")) {
size_t sptr = 0;
for (int i = 0; i < (maxdatalen / 8); i++) {
if (sptr + 8 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
if (!strcmp(ctype, "ndef")) {
json_error_t up_error = {0};
int i1 = 0;
size_t ndefsize = 0;
if (json_unpack_ex(root, &up_error, 0, "{s:i}", "Ndef.Size", &i1) == 0) {
ndefsize = i1;
}
size_t sptr = 0;
for (int i = 0; i < (maxdatalen / 16); i++) {
if (sptr + 16 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 16, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
goto out;
}
// unidentified file format
if (verbose) {
PrintAndLogEx(FAILED, "Unidentified file format `" _YELLOW_("%s") "`", path);
}
retval = PM3_EFILE;
out:
if (callback != NULL) {
@ -2082,17 +2318,20 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con
int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) {
int res = 0;
int res = PM3_SUCCESS;
DumpFileType_t dftype = getfiletype(fn);
switch (dftype) {
case BIN: {
res = loadFile_safe(fn, ".bin", pdump, dumplen);
loadFile_safe(fn, ".bin", pdump, dumplen);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "File IO failed");
}
break;
}
case EML: {
res = loadFileEML_safe(fn, pdump, dumplen);
if (res == PM3_ESOFT) {
PrintAndLogEx(WARNING, "file IO failed");
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "File IO failed");
}
break;
}
@ -2103,8 +2342,9 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
return PM3_EMALLOC;
}
res = loadFileJSON(fn, *pdump, maxdumplen, dumplen, NULL);
if (res == PM3_SUCCESS)
if (res == PM3_SUCCESS) {
return res;
}
free(*pdump);
@ -2116,7 +2356,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
break;
}
case DICTIONARY: {
PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed");
PrintAndLogEx(ERR, "Only BIN/EML/JSON formats allowed");
return PM3_EINVARG;
}
case MCT: {
@ -2128,15 +2368,49 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
return res;
}
int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize) {
int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
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);
saveFileEML(fn, d, n, blocksize);
saveFileJSON(fn, jsft, d, n, NULL);
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) {
PrintAndLogEx(INFO, "No data to save, skipping...");
return PM3_EINVARG;
}
saveFile(fn, ".bin", d, n);
iso14a_mf_extdump_t jd = {0};
jd.card_info.ats_len = 0;
// Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA
if ((d[0] ^ d[1] ^ d[2] ^ d[3]) == d[4] && (d[6] & 0xC0) == 0) {
jd.card_info.uidlen = 4;
memcpy(jd.card_info.uid, d, jd.card_info.uidlen);
jd.card_info.sak = d[5];
memcpy(jd.card_info.atqa, &d[6], sizeof(jd.card_info.atqa));
}
// Check for 7 bytes UID: double size uid bits in ATQA
else if ((d[8] & 0xC0) == 0x40) {
jd.card_info.uidlen = 7;
memcpy(jd.card_info.uid, d, jd.card_info.uidlen);
jd.card_info.sak = d[7];
memcpy(jd.card_info.atqa, &d[8], sizeof(jd.card_info.atqa));
} else {
PrintAndLogEx(WARNING, "Invalid dump. UID/SAK/ATQA not found");
}
jd.dump = d;
jd.dumplen = n;
saveFileJSON(fn, jsfMfc_v2, (uint8_t *)&jd, sizeof(jd), NULL);
return PM3_SUCCESS;
}

View file

@ -29,15 +29,32 @@
#include "mifare/mifarehost.h"
#include "cmdhfmfu.h"
#include "protocols.h" // iclass defines
#include "cmdhftopaz.h" // TOPAZ defines
#include "mifare/mifaredefault.h" // MFP / AES defines
typedef union {
void *v;
uint8_t *bytes;
mfu_dump_t *mfu;
topaz_tag_t *topaz;
iso14a_mf_extdump_t *mfc;
} udata_t;
typedef enum {
jsfRaw,
jsfCardMemory,
jsfMfc_v2,
jsfMfuMemory,
jsfHitag,
jsfIclass,
jsf14b,
jsf14b_v2,
jsf15,
jsf15_v2,
jsf15_v3,
jsfLegic,
jsfLegic_v2,
jsfT55x7,
jsfT5555,
jsfMfPlusKeys,
@ -49,6 +66,9 @@ typedef enum {
jsfFido,
jsfFudan,
jsfTopaz,
jsfLto,
jsfCryptorf,
jsfNDEF,
} JSONFileType;
typedef enum {
@ -276,18 +296,33 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
/** STUB
* @brief Utility function to save data to three file files (BIN/EML/JSON).
* @brief Utility function to save data to three file files (BIN/JSON).
* It also tries to save according to user preferences set dump folder paths.
* E.g. dumpdata.bin
* E.g. dumpdata.eml
* E.g. dumpdata.json
*
* @param fn
* @param d The binary data to write to the file
* @param n the length of the data
* @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc)
* @param blocksize
* @return PM3_SUCCESS if OK
*/
int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize);
int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
/** STUB
* @brief Utility function to save data to three file files (BIN/JSON).
* It also tries to save according to user preferences set dump folder paths.
* E.g. dumpdata.bin
* E.g. dumpdata.json
*
* This function is dedicated for MIFARE CLASSIC dumps. Checking for 4 or 7 byte UID in indata.
* Saves the corrected data in the json file
*
* @param fn
* @param d The binary data to write to the file
* @param n the length of the data
* @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc)
* @return PM3_SUCCESS if OK
*/
int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
#endif // FILEUTILS_H

View file

@ -1278,3 +1278,33 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) {
}
return PM3_SUCCESS;
}
int NDEFGetTotalLength(uint8_t *ndef, size_t ndeflen, size_t *outlen) {
size_t idx = 0;
while (idx < ndeflen) {
if (ndef[idx] == 0x00 ||
ndef[idx] == 0x01 ||
ndef[idx] == 0x02 ||
ndef[idx] == 0x03 ||
ndef[idx] == 0xFD) {
idx++;
idx += ndefTLVGetLength(&ndef[idx], &idx);
continue;
}
if (ndef[idx] == 0xFE) {
idx++;
break;
}
// invalid NDEF
*outlen = 0;
return PM3_ESOFT;
}
*outlen = idx;
return PM3_SUCCESS;
}

View file

@ -76,5 +76,5 @@ typedef struct {
int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose);
int NDEFRecordsDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen, bool verbose);
int NDEFGetTotalLength(uint8_t *ndef, size_t ndeflen, size_t *outlen);
#endif // _NDEF_H_

View file

@ -24,7 +24,7 @@
//-----------------------------------------------------------------------------
// iCLASS / PICOPASS
//-----------------------------------------------------------------------------
#define PICOPASS_BLOCK_SIZE 8
// iCLASS reader flags
#define FLAG_ICLASS_READER_INIT 0x01