mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 13:00:42 -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...")
|
||||
cmd = f"hf mf isen --collect_fm11rf08s_with_data --key {BACKDOOR_RF08S}"
|
||||
p.console(cmd)
|
||||
try:
|
||||
nt, nt_enc, par_err, data = json.loads(p.grabbed_output)
|
||||
except json.decoder.JSONDecodeError:
|
||||
nonces_with_data = ""
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
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.")
|
||||
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")
|
||||
dumpfile = f"hf-mf-{uid:08X}-dump.bin"
|
||||
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_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_str0("f", "file", "<fn>", "Specify a filename for collected data"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -9827,6 +9828,10 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
|||
if (collect_fm11rf08s_with_data) {
|
||||
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);
|
||||
|
||||
uint8_t dbg_curr = DBG_NONE;
|
||||
|
@ -9881,32 +9886,21 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
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++) {
|
||||
PrintAndLogEx(NORMAL, " [\"%08x\", \"%08x\"]%s",
|
||||
(uint32_t) bytes_to_num(resp.data.asBytes + ((sec * 2) * 9), 4),
|
||||
(uint32_t) bytes_to_num(resp.data.asBytes + (((sec * 2) + 1) * 9), 4),
|
||||
sec < num_sectors - 1 ? "," : "");
|
||||
memcpy(nonces_dump.nt[sec][0], resp.data.asBytes + ((sec * 2) * 9), 4);
|
||||
memcpy(nonces_dump.nt[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9), 4);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, " ],\n [");
|
||||
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
||||
PrintAndLogEx(NORMAL, " [\"%08x\", \"%08x\"]%s",
|
||||
(uint32_t) bytes_to_num(resp.data.asBytes + ((sec * 2) * 9) + 4, 4),
|
||||
(uint32_t) bytes_to_num(resp.data.asBytes + (((sec * 2) + 1) * 9) + 4, 4),
|
||||
sec < num_sectors - 1 ? "," : "");
|
||||
memcpy(nonces_dump.nt_enc[sec][0], resp.data.asBytes + ((sec * 2) * 9) + 4, 4);
|
||||
memcpy(nonces_dump.nt_enc[sec][1], resp.data.asBytes + (((sec * 2) + 1) * 9) + 4, 4);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, " ],\n [");
|
||||
for (uint8_t sec = 0; sec < num_sectors; sec++) {
|
||||
uint8_t p0 = resp.data.asBytes[((sec * 2) * 9) + 8];
|
||||
uint8_t p1 = 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 ? "," : "");
|
||||
nonces_dump.par_err[sec][0] = resp.data.asBytes[((sec * 2) * 9) + 8];
|
||||
nonces_dump.par_err[sec][1] = resp.data.asBytes[(((sec * 2) + 1) * 9) + 8];
|
||||
}
|
||||
if (collect_fm11rf08s_with_data) {
|
||||
PrintAndLogEx(NORMAL, " ],\n [");
|
||||
int bytes = MIFARE_1K_MAXSECTOR * 4 * 16;
|
||||
int bytes = MIFARE_1K_MAXBLOCK * MFBLOCK_SIZE;
|
||||
|
||||
uint8_t *dump = calloc(bytes, sizeof(uint8_t));
|
||||
if (dump == NULL) {
|
||||
|
@ -9918,16 +9912,17 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
|||
free(dump);
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
for (uint8_t sec = 0; sec < MIFARE_1K_MAXSECTOR; sec++) {
|
||||
for (uint8_t b = 0; b < 4; b++) {
|
||||
PrintAndLogEx(NORMAL, " \"%s\"%s",
|
||||
sprint_hex_inrow(dump + ((sec * 4) + b) * 16, 16),
|
||||
(sec == MIFARE_1K_MAXSECTOR - 1) && (b == 3) ? "" : ",");
|
||||
}
|
||||
for (uint8_t blk = 0; blk < MIFARE_1K_MAXBLOCK; blk++) {
|
||||
memcpy(nonces_dump.blocks[blk], dump + blk * MFBLOCK_SIZE, MFBLOCK_SIZE);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -712,6 +712,52 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
|||
}
|
||||
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
|
||||
case jsfFido:
|
||||
break;
|
||||
|
@ -737,7 +783,6 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
|||
free(fn);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
jsfCryptorf,
|
||||
jsfNDEF,
|
||||
jsfFM11RF08SNonces,
|
||||
jsfFM11RF08SNoncesWithData
|
||||
} JSONFileType;
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -84,6 +84,12 @@ typedef struct {
|
|||
uint8_t *dump;
|
||||
} 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 {
|
||||
ISO14A_CONNECT = (1 << 0),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue