mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
fm11rf08s_nonces_with_data: save in JSON file
This commit is contained in:
parent
c002ae9f77
commit
080ddc1595
5 changed files with 134 additions and 30 deletions
|
@ -112,12 +112,42 @@ if args.init_check:
|
||||||
print("Getting nonces...")
|
print("Getting nonces...")
|
||||||
cmd = f"hf mf isen --collect_fm11rf08s_with_data --key {BACKDOOR_RF08S}"
|
cmd = f"hf mf isen --collect_fm11rf08s_with_data --key {BACKDOOR_RF08S}"
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
try:
|
nonces_with_data = ""
|
||||||
nt, nt_enc, par_err, data = json.loads(p.grabbed_output)
|
for line in p.grabbed_output.split('\n'):
|
||||||
except json.decoder.JSONDecodeError:
|
if "Wrong" in line or "error" in line:
|
||||||
|
print("Error getting nonces, abort.")
|
||||||
|
exit()
|
||||||
|
if "Saved" in line:
|
||||||
|
nonces_with_data = line[line.index("`"):].strip("`")
|
||||||
|
if (nonces_with_data == ""):
|
||||||
print("Error getting nonces, abort.")
|
print("Error getting nonces, abort.")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(nonces_with_data, 'r') as file:
|
||||||
|
# Load and parse the JSON data
|
||||||
|
dict_nwd = json.load(file)
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
print(f"Error parsing {nonces_with_data}, abort.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
nt = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
|
nt_enc = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
|
par_err = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
|
data = ["" for _ in range(NUM_SECTORS * 4)]
|
||||||
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
|
real_sec = sec
|
||||||
|
if sec >= NUM_SECTORS:
|
||||||
|
real_sec += 16
|
||||||
|
nt[sec][0] = dict_nwd["nt"][f"{real_sec}"]["a"].lower()
|
||||||
|
nt[sec][1] = dict_nwd["nt"][f"{real_sec}"]["b"].lower()
|
||||||
|
nt_enc[sec][0] = dict_nwd["nt_enc"][f"{real_sec}"]["a"].lower()
|
||||||
|
nt_enc[sec][1] = dict_nwd["nt_enc"][f"{real_sec}"]["b"].lower()
|
||||||
|
par_err[sec][0] = dict_nwd["par_err"][f"{real_sec}"]["a"]
|
||||||
|
par_err[sec][1] = dict_nwd["par_err"][f"{real_sec}"]["b"]
|
||||||
|
for blk in range(NUM_SECTORS * 4):
|
||||||
|
data[blk] = dict_nwd["blocks"][f"{blk}"]
|
||||||
|
|
||||||
print("Generating first dump file")
|
print("Generating first dump file")
|
||||||
dumpfile = f"hf-mf-{uid:08X}-dump.bin"
|
dumpfile = f"hf-mf-{uid:08X}-dump.bin"
|
||||||
with (open(dumpfile, "wb")) as f:
|
with (open(dumpfile, "wb")) as f:
|
||||||
|
|
|
@ -9757,6 +9757,7 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
||||||
arg_rem("FM11RF08S specific options:", "Incompatible with above options, except -k; output in JSON"),
|
arg_rem("FM11RF08S specific options:", "Incompatible with above options, except -k; output in JSON"),
|
||||||
arg_lit0(NULL, "collect_fm11rf08s", "collect all nT/{nT}/par_err."),
|
arg_lit0(NULL, "collect_fm11rf08s", "collect all nT/{nT}/par_err."),
|
||||||
arg_lit0(NULL, "collect_fm11rf08s_with_data", "collect all nT/{nT}/par_err and data blocks."),
|
arg_lit0(NULL, "collect_fm11rf08s_with_data", "collect all nT/{nT}/par_err and data blocks."),
|
||||||
|
arg_str0("f", "file", "<fn>", "Specify a filename for collected data"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -9827,6 +9828,10 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
||||||
if (collect_fm11rf08s_with_data) {
|
if (collect_fm11rf08s_with_data) {
|
||||||
collect_fm11rf08s = 1;
|
collect_fm11rf08s = 1;
|
||||||
}
|
}
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 23), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
uint8_t dbg_curr = DBG_NONE;
|
uint8_t dbg_curr = DBG_NONE;
|
||||||
|
@ -9881,32 +9886,21 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t num_sectors = MIFARE_1K_MAXSECTOR + 1;
|
uint8_t num_sectors = MIFARE_1K_MAXSECTOR + 1;
|
||||||
PrintAndLogEx(NORMAL, "[\n [");
|
iso14a_fm11rf08s_nonces_with_data_t nonces_dump = {0};
|
||||||
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
||||||
PrintAndLogEx(NORMAL, " [\"%08x\", \"%08x\"]%s",
|
memcpy(nonces_dump.nt[sec][0], resp.data.asBytes + ((sec * 2) * 9), 4);
|
||||||
(uint32_t) bytes_to_num(resp.data.asBytes + ((sec * 2) * 9), 4),
|
memcpy(nonces_dump.nt[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9), 4);
|
||||||
(uint32_t) bytes_to_num(resp.data.asBytes + (((sec * 2) + 1) * 9), 4),
|
|
||||||
sec < num_sectors - 1 ? "," : "");
|
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " ],\n [");
|
|
||||||
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
||||||
PrintAndLogEx(NORMAL, " [\"%08x\", \"%08x\"]%s",
|
memcpy(nonces_dump.nt_enc[sec][0], resp.data.asBytes + ((sec * 2) * 9) + 4, 4);
|
||||||
(uint32_t) bytes_to_num(resp.data.asBytes + ((sec * 2) * 9) + 4, 4),
|
memcpy(nonces_dump.nt_enc[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9) + 4, 4);
|
||||||
(uint32_t) bytes_to_num(resp.data.asBytes + (((sec * 2) + 1) * 9) + 4, 4),
|
|
||||||
sec < num_sectors - 1 ? "," : "");
|
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " ],\n [");
|
|
||||||
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
||||||
uint8_t p0 = resp.data.asBytes[((sec * 2) * 9) + 8];
|
nonces_dump.par_err[sec][0] = resp.data.asBytes[((sec * 2) * 9) + 8];
|
||||||
uint8_t p1 = resp.data.asBytes[(((sec * 2) + 1) * 9) + 8];
|
nonces_dump.par_err[sec][1] = resp.data.asBytes[(((sec * 2) + 1) * 9) + 8];
|
||||||
PrintAndLogEx(NORMAL, " [\"%i%i%i%i\", \"%i%i%i%i\"]%s",
|
|
||||||
(p0 >> 3) & 1, (p0 >> 2) & 1, (p0 >> 1) & 1, p0 & 1,
|
|
||||||
(p1 >> 3) & 1, (p1 >> 2) & 1, (p1 >> 1) & 1, p1 & 1,
|
|
||||||
sec < num_sectors - 1 ? "," : "");
|
|
||||||
}
|
}
|
||||||
if (collect_fm11rf08s_with_data) {
|
if (collect_fm11rf08s_with_data) {
|
||||||
PrintAndLogEx(NORMAL, " ],\n [");
|
int bytes = MIFARE_1K_MAXBLOCK * MFBLOCK_SIZE;
|
||||||
int bytes = MIFARE_1K_MAXSECTOR * 4 * 16;
|
|
||||||
|
|
||||||
uint8_t *dump = calloc(bytes, sizeof(uint8_t));
|
uint8_t *dump = calloc(bytes, sizeof(uint8_t));
|
||||||
if (dump == NULL) {
|
if (dump == NULL) {
|
||||||
|
@ -9918,16 +9912,17 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
for (uint8_t sec = 0; sec < MIFARE_1K_MAXSECTOR; sec++) {
|
for (uint8_t blk = 0; blk < MIFARE_1K_MAXBLOCK; blk++) {
|
||||||
for (uint8_t b = 0; b < 4; b++) {
|
memcpy(nonces_dump.blocks[blk], dump + blk * MFBLOCK_SIZE, MFBLOCK_SIZE);
|
||||||
PrintAndLogEx(NORMAL, " \"%s\"%s",
|
|
||||||
sprint_hex_inrow(dump + ((sec * 4) + b) * 16, 16),
|
|
||||||
(sec == MIFARE_1K_MAXSECTOR - 1) && (b == 3) ? "" : ",");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(dump);
|
free(dump);
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " ]\n]");
|
if (fnlen == 0) {
|
||||||
|
snprintf(filename, sizeof(filename), "hf-mf-%s-nonces%s", sprint_hex_inrow(card.uid, card.uidlen), collect_fm11rf08s_with_data ? "_with_data" : "");
|
||||||
|
}
|
||||||
|
if (pm3_save_fm11rf08s_nonces(filename, &nonces_dump, collect_fm11rf08s_with_data) != PM3_SUCCESS) {
|
||||||
|
return PM3_EFAILED;
|
||||||
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -712,6 +712,52 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case jsfFM11RF08SNonces:
|
||||||
|
case jsfFM11RF08SNoncesWithData: {
|
||||||
|
if (datalen != sizeof(iso14a_fm11rf08s_nonces_with_data_t)) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
iso14a_fm11rf08s_nonces_with_data_t * p = (iso14a_fm11rf08s_nonces_with_data_t *)data;
|
||||||
|
if (ftype == jsfFM11RF08SNoncesWithData) {
|
||||||
|
JsonSaveStr(root, "FileType", "fm11rf08s_nonces_with_data");
|
||||||
|
} else {
|
||||||
|
JsonSaveStr(root, "FileType", "fm11rf08s_nonces");
|
||||||
|
}
|
||||||
|
for (uint16_t sec = 0; sec < MIFARE_1K_MAXSECTOR + 1; sec++) {
|
||||||
|
uint8_t par2[2];
|
||||||
|
uint8_t par;
|
||||||
|
uint16_t real_sec = sec;
|
||||||
|
if (sec == MIFARE_1K_MAXSECTOR) {
|
||||||
|
real_sec = 32; // advanced verification method block
|
||||||
|
}
|
||||||
|
snprintf(path, sizeof(path), "$.nt.%u.a", real_sec);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, p->nt[sec][0], 4);
|
||||||
|
snprintf(path, sizeof(path), "$.nt.%u.b", real_sec);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, p->nt[sec][1], 4);
|
||||||
|
snprintf(path, sizeof(path), "$.nt_enc.%u.a", real_sec);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, p->nt_enc[sec][0], 4);
|
||||||
|
snprintf(path, sizeof(path), "$.nt_enc.%u.b", real_sec);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, p->nt_enc[sec][1], 4);
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "$.par_err.%u.a", real_sec);
|
||||||
|
par = p->par_err[sec][0];
|
||||||
|
par2[0] = (((par >> 3) & 1) << 4) | ((par >> 2) & 1);
|
||||||
|
par2[1] = (((par >> 1) & 1) << 4) | ((par >> 0) & 1);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, par2, 2);
|
||||||
|
snprintf(path, sizeof(path), "$.par_err.%u.b", real_sec);
|
||||||
|
par = p->par_err[sec][1];
|
||||||
|
par2[0] = (((par >> 3) & 1) << 4) | ((par >> 2) & 1);
|
||||||
|
par2[1] = (((par >> 1) & 1) << 4) | ((par >> 0) & 1);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, par2, 2);
|
||||||
|
}
|
||||||
|
if (ftype == jsfFM11RF08SNoncesWithData) {
|
||||||
|
for (uint16_t blk = 0; blk < MIFARE_1K_MAXBLOCK; blk++) {
|
||||||
|
snprintf(path, sizeof(path), "$.blocks.%u", blk);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, p->blocks[blk], MFBLOCK_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
// no action
|
// no action
|
||||||
case jsfFido:
|
case jsfFido:
|
||||||
break;
|
break;
|
||||||
|
@ -737,7 +783,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
||||||
free(fn);
|
free(fn);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(SUCCESS, "Saved to json file `" _YELLOW_("%s") "`", fn);
|
PrintAndLogEx(SUCCESS, "Saved to json file `" _YELLOW_("%s") "`", fn);
|
||||||
}
|
}
|
||||||
|
@ -3111,3 +3156,18 @@ int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pm3_save_fm11rf08s_nonces(const char *fn, iso14a_fm11rf08s_nonces_with_data_t *d, bool with_data) {
|
||||||
|
|
||||||
|
if (fn == NULL || d == NULL) {
|
||||||
|
PrintAndLogEx(INFO, "No data to save, skipping...");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (with_data) {
|
||||||
|
saveFileJSON(fn, jsfFM11RF08SNoncesWithData, (uint8_t *)d, sizeof(*d), NULL);
|
||||||
|
} else {
|
||||||
|
saveFileJSON(fn, jsfFM11RF08SNonces, (uint8_t *)d, sizeof(*d), NULL);
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,8 @@ typedef enum {
|
||||||
jsfLto,
|
jsfLto,
|
||||||
jsfCryptorf,
|
jsfCryptorf,
|
||||||
jsfNDEF,
|
jsfNDEF,
|
||||||
|
jsfFM11RF08SNonces,
|
||||||
|
jsfFM11RF08SNoncesWithData
|
||||||
} JSONFileType;
|
} JSONFileType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -346,4 +348,15 @@ int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
|
||||||
* @return PM3_SUCCESS if OK
|
* @return PM3_SUCCESS if OK
|
||||||
*/
|
*/
|
||||||
int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
|
int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
|
||||||
|
|
||||||
|
/** STUB
|
||||||
|
* @brief Utility function to save FM11RF08S recovery data.
|
||||||
|
*
|
||||||
|
* @param fn
|
||||||
|
* @param d iso14a_fm11rf08s_nonces_with_data_t structure
|
||||||
|
* @param n the length of the structure
|
||||||
|
* @param with_data does the structure contain data blocks?
|
||||||
|
* @return PM3_SUCCESS if OK
|
||||||
|
*/
|
||||||
|
int pm3_save_fm11rf08s_nonces(const char *fn, iso14a_fm11rf08s_nonces_with_data_t *d, bool with_data);
|
||||||
#endif // FILEUTILS_H
|
#endif // FILEUTILS_H
|
||||||
|
|
|
@ -84,6 +84,12 @@ typedef struct {
|
||||||
uint8_t *dump;
|
uint8_t *dump;
|
||||||
} iso14a_mf_dump_ev1_t;
|
} iso14a_mf_dump_ev1_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t nt[17][2][4];
|
||||||
|
uint8_t nt_enc[17][2][4];
|
||||||
|
uint8_t par_err[17][2];
|
||||||
|
uint8_t blocks[64][16]; // [MIFARE_1K_MAXSECTOR * 4][MFBLOCK_SIZE]
|
||||||
|
} iso14a_fm11rf08s_nonces_with_data_t;
|
||||||
|
|
||||||
typedef enum ISO14A_COMMAND {
|
typedef enum ISO14A_COMMAND {
|
||||||
ISO14A_CONNECT = (1 << 0),
|
ISO14A_CONNECT = (1 << 0),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue