1 /*****************************************************************************
4 * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
6 * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
7 * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
8 * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
10 * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
12 *****************************************************************************
14 * This file is part of loclass. It is a reconstructon of the cipher engine
15 * used in iClass, and RFID techology.
17 * The implementation is based on the work performed by
18 * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
19 * Milosch Meriac in the paper "Dismantling IClass".
21 * Copyright (C) 2014 Martin Holst Swende
23 * This is free software: you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License version 2 as published
25 * by the Free Software Foundation, or, at your option, any later version.
27 * This file is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with loclass. If not, see <http://www.gnu.org/licenses/>.
36 ****************************************************************************/
38 // this define is needed for scandir/alphasort to work
40 #include "fileutils.h"
41 #include "preferences.h"
47 #include "commonutil.h"
48 #include "proxmark3.h"
50 #include "cmdhficlass.h" // pagemap
51 #include "protocols.h" // iclass defines
58 #define PATH_MAX_LENGTH 200
69 uint32_t sample_per_sec
;
70 uint32_t byte_per_sec
;
72 uint16_t bit_per_sample
;
81 * @brief detects if file is of a supported filetype based on extension
85 DumpFileType_t
getfiletype(const char *filename
) {
86 // assume unknown file is BINARY
87 DumpFileType_t o
= BIN
;
88 if (filename
== NULL
) {
92 size_t len
= strlen(filename
);
94 // check if valid file extension and attempt to load data
95 char s
[FILE_PATH_SIZE
];
96 memset(s
, 0, sizeof(s
));
97 memcpy(s
, filename
, len
);
100 if (str_endswith(s
, "bin")) {
102 } else if (str_endswith(s
, "eml")) {
104 } else if (str_endswith(s
, "json")) {
106 } else if (str_endswith(s
, "dic")) {
109 // mfd, trc, trace is binary
112 // .pm3 is text values of signal data
119 * @brief checks if a file exists
123 int fileExists(const char *filename
) {
127 int result
= _stat(filename
, &st
);
130 int result
= stat(filename
, &st
);
136 * @brief checks if path is file.
141 static bool is_regular_file(const char *filename) {
144 if (_stat(filename, &st) == -1)
148 // stat(filename, &st);
149 if (lstat(filename, &st) == -1)
152 return S_ISREG(st.st_mode) != 0;
157 * @brief checks if path is directory.
161 static bool is_directory(const char *filename
) {
164 if (_stat(filename
, &st
) == -1)
168 // stat(filename, &st);
169 if (lstat(filename
, &st
) == -1)
172 return S_ISDIR(st
.st_mode
) != 0;
176 * @brief create a new directory.
183 #define make_dir(a) _mkdir(a)
185 #define make_dir(a) mkdir(a,0755) //note 0755 MUST have leading 0 for octal linux file permissions
187 bool create_path(const char *dirname) {
189 if (dirname == NULL) // nothing to do
192 if ((strlen(dirname) == 1) && (dirname[0] == '/'))
195 if ((strlen(dirname) == 2) && (dirname[1] == ':'))
198 if (fileExists(dirname) == 0) {
200 char *bs = strrchr(dirname, '\\');
201 char *fs = strrchr(dirname, '/');
203 if ((bs == NULL) && (fs != NULL)) {
205 create_path (dirname);
209 if ((bs != NULL) && (fs == NULL)) {
211 create_path (dirname);
215 if ((bs != NULL) && (fs != NULL)) {
216 if (strlen (bs) > strlen (fs)) {
217 *fs = 0x00; // No slash
218 create_path (dirname);
222 create_path (dirname);
228 if (make_dir(dirname) != 0) {
229 PrintAndLogEx(ERR, "could not create directory.... "_RED_("%s"),dirname);
237 bool setDefaultPath(savePaths_t pathIndex
, const char *Path
) {
239 if (pathIndex
< spItemCount
) {
240 if ((Path
== NULL
) && (session
.defaultPaths
[pathIndex
] != NULL
)) {
241 free(session
.defaultPaths
[pathIndex
]);
242 session
.defaultPaths
[pathIndex
] = NULL
;
246 session
.defaultPaths
[pathIndex
] = (char *)realloc(session
.defaultPaths
[pathIndex
], strlen(Path
) + 1);
247 strcpy(session
.defaultPaths
[pathIndex
], Path
);
254 static char *filenamemcopy(const char *preferredName
, const char *suffix
) {
255 if (preferredName
== NULL
) return NULL
;
256 if (suffix
== NULL
) return NULL
;
257 char *fileName
= (char *) calloc(strlen(preferredName
) + strlen(suffix
) + 1, sizeof(uint8_t));
258 if (fileName
== NULL
)
260 strcpy(fileName
, preferredName
);
261 if (str_endswith(fileName
, suffix
))
263 strcat(fileName
, suffix
);
267 char *newfilenamemcopy(const char *preferredName
, const char *suffix
) {
268 if (preferredName
== NULL
) return NULL
;
269 if (suffix
== NULL
) return NULL
;
271 uint16_t p_namelen
= strlen(preferredName
);
272 if (str_endswith(preferredName
, suffix
))
273 p_namelen
-= strlen(suffix
);
275 char *fileName
= (char *) calloc(p_namelen
+ strlen(suffix
) + 1 + 10, sizeof(uint8_t)); // 10: room for filenum to ensure new filename
276 if (fileName
== NULL
) {
281 sprintf(fileName
, "%.*s%s", p_namelen
, preferredName
, suffix
);
282 while (fileExists(fileName
)) {
283 sprintf(fileName
, "%.*s-%d%s", p_namelen
, preferredName
, num
, suffix
);
289 int saveFile(const char *preferredName
, const char *suffix
, const void *data
, size_t datalen
) {
291 if (data
== NULL
) return PM3_EINVARG
;
292 char *fileName
= newfilenamemcopy(preferredName
, suffix
);
293 if (fileName
== NULL
) return PM3_EMALLOC
;
295 /* We should have a valid filename now, e.g. dumpdata-3.bin */
297 /*Opening file for writing in binary mode*/
298 FILE *f
= fopen(fileName
, "wb");
300 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", fileName
);
304 fwrite(data
, 1, datalen
, f
);
307 PrintAndLogEx(SUCCESS
, "saved " _YELLOW_("%zu") " bytes to binary file " _YELLOW_("%s"), datalen
, fileName
);
312 int saveFileEML(const char *preferredName
, uint8_t *data
, size_t datalen
, size_t blocksize
) {
314 if (data
== NULL
) return PM3_EINVARG
;
315 char *fileName
= newfilenamemcopy(preferredName
, ".eml");
316 if (fileName
== NULL
) return PM3_EMALLOC
;
318 int retval
= PM3_SUCCESS
;
319 int blocks
= datalen
/ blocksize
;
320 uint16_t currblock
= 1;
322 /* We should have a valid filename now, e.g. dumpdata-3.bin */
324 /*Opening file for writing in text mode*/
325 FILE *f
= fopen(fileName
, "w+");
327 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", fileName
);
332 for (size_t i
= 0; i
< datalen
; i
++) {
333 fprintf(f
, "%02X", data
[i
]);
335 // no extra line in the end
336 if ((i
+ 1) % blocksize
== 0 && currblock
!= blocks
) {
342 if (datalen
% blocksize
!= 0) {
343 int index
= blocks
* blocksize
;
344 for (size_t j
= 0; j
< datalen
% blocksize
; j
++) {
345 fprintf(f
, "%02X", data
[index
+ j
]);
350 PrintAndLogEx(SUCCESS
, "saved " _YELLOW_("%" PRId32
) " blocks to text file " _YELLOW_("%s"), blocks
, fileName
);
357 int saveFileJSON(const char *preferredName
, JSONFileType ftype
, uint8_t *data
, size_t datalen
, void (*callback
)(json_t
*)) {
358 return saveFileJSONex(preferredName
, ftype
, data
, datalen
, true, callback
);
360 int saveFileJSONex(const char *preferredName
, JSONFileType ftype
, uint8_t *data
, size_t datalen
, bool verbose
, void (*callback
)(json_t
*)) {
362 if (data
== NULL
) return PM3_EINVARG
;
364 char *fileName
= newfilenamemcopy(preferredName
, ".json");
365 if (fileName
== NULL
) return PM3_EMALLOC
;
367 int retval
= PM3_SUCCESS
;
369 json_t
*root
= json_object();
370 JsonSaveStr(root
, "Created", "proxmark3");
373 JsonSaveStr(root
, "FileType", "raw");
374 JsonSaveBufAsHexCompact(root
, "raw", data
, datalen
);
377 case jsfCardMemory
: {
378 JsonSaveStr(root
, "FileType", "mfcard");
379 for (size_t i
= 0; i
< (datalen
/ 16); i
++) {
380 char path
[PATH_MAX_LENGTH
] = {0};
381 sprintf(path
, "$.blocks.%zu", i
);
382 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16], 16);
385 JsonSaveBufAsHexCompact(root
, "$.Card.UID", &data
[0], 4);
386 JsonSaveBufAsHexCompact(root
, "$.Card.SAK", &data
[5], 1);
387 JsonSaveBufAsHexCompact(root
, "$.Card.ATQA", &data
[6], 2);
390 if (mfIsSectorTrailer(i
)) {
392 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.KeyA", mfSectorNum(i
));
393 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16], 6);
395 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.KeyB", mfSectorNum(i
));
396 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16 + 10], 6);
398 uint8_t *adata
= &data
[i
* 16 + 6];
399 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.AccessConditions", mfSectorNum(i
));
400 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16 + 6], 4);
402 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i
), i
- 3);
403 JsonSaveStr(root
, path
, mfGetAccessConditionsDesc(0, adata
));
405 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i
), i
- 2);
406 JsonSaveStr(root
, path
, mfGetAccessConditionsDesc(1, adata
));
408 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i
), i
- 1);
409 JsonSaveStr(root
, path
, mfGetAccessConditionsDesc(2, adata
));
411 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i
), i
);
412 JsonSaveStr(root
, path
, mfGetAccessConditionsDesc(3, adata
));
414 snprintf(path
, sizeof(path
), "$.SectorKeys.%d.AccessConditionsText.UserData", mfSectorNum(i
));
415 JsonSaveBufAsHexCompact(root
, path
, &adata
[3], 1);
421 JsonSaveStr(root
, "FileType", "mfu");
423 mfu_dump_t
*tmp
= (mfu_dump_t
*)data
;
425 uint8_t uid
[7] = {0};
426 memcpy(uid
, tmp
->data
, 3);
427 memcpy(uid
+ 3, tmp
->data
+ 4, 4);
429 char path
[PATH_MAX_LENGTH
] = {0};
431 JsonSaveBufAsHexCompact(root
, "$.Card.UID", uid
, sizeof(uid
));
432 JsonSaveBufAsHexCompact(root
, "$.Card.Version", tmp
->version
, sizeof(tmp
->version
));
433 JsonSaveBufAsHexCompact(root
, "$.Card.TBO_0", tmp
->tbo
, sizeof(tmp
->tbo
));
434 JsonSaveBufAsHexCompact(root
, "$.Card.TBO_1", tmp
->tbo1
, sizeof(tmp
->tbo1
));
435 JsonSaveBufAsHexCompact(root
, "$.Card.Signature", tmp
->signature
, sizeof(tmp
->signature
));
436 for (uint8_t i
= 0; i
< 3; i
++) {
437 sprintf(path
, "$.Card.Counter%d", i
);
438 JsonSaveBufAsHexCompact(root
, path
, tmp
->counter_tearing
[i
], 3);
439 sprintf(path
, "$.Card.Tearing%d", i
);
440 JsonSaveBufAsHexCompact(root
, path
, tmp
->counter_tearing
[i
] + 3, 1);
443 // size of header 56b
444 size_t len
= (datalen
- MFU_DUMP_PREFIX_LENGTH
) / 4;
446 for (size_t i
= 0; i
< len
; i
++) {
447 sprintf(path
, "$.blocks.%zu", i
);
448 JsonSaveBufAsHexCompact(root
, path
, tmp
->data
+ (i
* 4), 4);
453 JsonSaveStr(root
, "FileType", "hitag");
454 uint8_t uid
[4] = {0};
455 memcpy(uid
, data
, 4);
457 JsonSaveBufAsHexCompact(root
, "$.Card.UID", uid
, sizeof(uid
));
459 for (size_t i
= 0; i
< (datalen
/ 4); i
++) {
460 char path
[PATH_MAX_LENGTH
] = {0};
461 sprintf(path
, "$.blocks.%zu", i
);
462 JsonSaveBufAsHexCompact(root
, path
, data
+ (i
* 4), 4);
467 JsonSaveStr(root
, "FileType", "iclass");
469 picopass_hdr_t
*hdr
= (picopass_hdr_t
*)data
;
470 JsonSaveBufAsHexCompact(root
, "$.Card.CSN", hdr
->csn
, sizeof(hdr
->csn
));
471 JsonSaveBufAsHexCompact(root
, "$.Card.Configuration", (uint8_t *)&hdr
->conf
, sizeof(hdr
->conf
));
473 uint8_t pagemap
= get_pagemap(hdr
);
474 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
475 picopass_ns_hdr_t
*ns_hdr
= (picopass_ns_hdr_t
*)data
;
476 JsonSaveBufAsHexCompact(root
, "$.Card.AIA", ns_hdr
->app_issuer_area
, sizeof(ns_hdr
->app_issuer_area
));
478 JsonSaveBufAsHexCompact(root
, "$.Card.Epurse", hdr
->epurse
, sizeof(hdr
->epurse
));
479 JsonSaveBufAsHexCompact(root
, "$.Card.Kd", hdr
->key_d
, sizeof(hdr
->key_d
));
480 JsonSaveBufAsHexCompact(root
, "$.Card.Kc", hdr
->key_c
, sizeof(hdr
->key_c
));
481 JsonSaveBufAsHexCompact(root
, "$.Card.AIA", hdr
->app_issuer_area
, sizeof(hdr
->app_issuer_area
));
484 for (size_t i
= 0; i
< (datalen
/ 8); i
++) {
485 char path
[PATH_MAX_LENGTH
] = {0};
486 sprintf(path
, "$.blocks.%zu", i
);
487 JsonSaveBufAsHexCompact(root
, path
, data
+ (i
* 8), 8);
493 JsonSaveStr(root
, "FileType", "t55x7");
494 uint8_t conf
[4] = {0};
495 memcpy(conf
, data
, 4);
496 JsonSaveBufAsHexCompact(root
, "$.Card.ConfigBlock", conf
, sizeof(conf
));
498 for (size_t i
= 0; i
< (datalen
/ 4); i
++) {
499 char path
[PATH_MAX_LENGTH
] = {0};
500 sprintf(path
, "$.blocks.%zu", i
);
501 JsonSaveBufAsHexCompact(root
, path
, data
+ (i
* 4), 4);
506 JsonSaveStr(root
, "FileType", "14b");
507 JsonSaveBufAsHexCompact(root
, "raw", data
, datalen
);
511 JsonSaveStr(root
, "FileType", "15693");
512 JsonSaveBufAsHexCompact(root
, "raw", data
, datalen
);
516 JsonSaveStr(root
, "FileType", "legic");
517 JsonSaveBufAsHexCompact(root
, "raw", data
, datalen
);
521 JsonSaveStr(root
, "FileType", "t5555");
522 uint8_t conf
[4] = {0};
523 memcpy(conf
, data
, 4);
524 JsonSaveBufAsHexCompact(root
, "$.Card.ConfigBlock", conf
, sizeof(conf
));
526 for (size_t i
= 0; i
< (datalen
/ 4); i
++) {
527 char path
[PATH_MAX_LENGTH
] = {0};
528 sprintf(path
, "$.blocks.%zu", i
);
529 JsonSaveBufAsHexCompact(root
, path
, data
+ (i
* 4), 4);
534 JsonSaveStr(root
, "FileType", "EM4205/EM4305");
535 JsonSaveBufAsHexCompact(root
, "$.Card.UID", data
+ (1 * 4), 4);
536 JsonSaveBufAsHexCompact(root
, "$.Card.Config", data
+ (4 * 4), 4);
537 JsonSaveBufAsHexCompact(root
, "$.Card.Protection1", data
+ (14 * 4), 4);
538 JsonSaveBufAsHexCompact(root
, "$.Card.Protection2", data
+ (15 * 4), 4);
540 for (size_t i
= 0; i
< (datalen
/ 4); i
++) {
541 char path
[PATH_MAX_LENGTH
] = {0};
542 sprintf(path
, "$.blocks.%zu", i
);
543 JsonSaveBufAsHexCompact(root
, path
, data
+ (i
* 4), 4);
548 JsonSaveStr(root
, "FileType", "EM4469/EM4569");
549 JsonSaveBufAsHexCompact(root
, "$.Card.UID", data
+ (1 * 4), 4);
550 JsonSaveBufAsHexCompact(root
, "$.Card.Protection", data
+ (3 * 4), 4);
551 JsonSaveBufAsHexCompact(root
, "$.Card.Config", data
+ (4 * 4), 4);
553 for (size_t i
= 0; i
< (datalen
/ 4); i
++) {
554 char path
[PATH_MAX_LENGTH
] = {0};
555 sprintf(path
, "$.blocks.%zu", i
);
556 JsonSaveBufAsHexCompact(root
, path
, data
+ (i
* 4), 4);
561 JsonSaveStr(root
, "FileType", "EM4X50");
562 JsonSaveBufAsHexCompact(root
, "$.Card.Protection", data
+ (1 * 4), 4);
563 JsonSaveBufAsHexCompact(root
, "$.Card.Config", data
+ (2 * 4), 4);
564 JsonSaveBufAsHexCompact(root
, "$.Card.Serial", data
+ (32 * 4), 4);
565 JsonSaveBufAsHexCompact(root
, "$.Card.UID", data
+ (33 * 4), 4);
567 for (size_t i
= 0; i
< (datalen
/ 4); i
++) {
568 char path
[PATH_MAX_LENGTH
] = {0};
569 sprintf(path
, "$.blocks.%zu", i
);
570 JsonSaveBufAsHexCompact(root
, path
, data
+ (i
* 4), 4);
574 case jsfMfPlusKeys
: {
575 JsonSaveStr(root
, "FileType", "mfp");
576 JsonSaveBufAsHexCompact(root
, "$.Card.UID", &data
[0], 7);
577 JsonSaveBufAsHexCompact(root
, "$.Card.SAK", &data
[10], 1);
578 JsonSaveBufAsHexCompact(root
, "$.Card.ATQA", &data
[11], 2);
579 uint8_t atslen
= data
[13];
581 JsonSaveBufAsHexCompact(root
, "$.Card.ATS", &data
[14], atslen
);
583 uint8_t vdata
[2][64][16 + 1] = {{{0}}};
584 memcpy(vdata
, &data
[14 + atslen
], 2 * 64 * 17);
586 for (size_t i
= 0; i
< datalen
; i
++) {
587 char path
[PATH_MAX_LENGTH
] = {0};
589 if (vdata
[0][i
][0]) {
590 memset(path
, 0x00, sizeof(path
));
591 sprintf(path
, "$.SectorKeys.%d.KeyA", mfSectorNum(i
));
592 JsonSaveBufAsHexCompact(root
, path
, &vdata
[0][i
][1], 16);
595 if (vdata
[1][i
][0]) {
596 memset(path
, 0x00, sizeof(path
));
597 sprintf(path
, "$.SectorKeys.%d.KeyB", mfSectorNum(i
));
598 JsonSaveBufAsHexCompact(root
, path
, &vdata
[1][i
][1], 16);
603 case jsfMfDesfireKeys
: {
604 JsonSaveStr(root
, "FileType", "mfdes");
605 JsonSaveBufAsHexCompact(root
, "$.Card.UID", &data
[0], 7);
606 JsonSaveBufAsHexCompact(root
, "$.Card.SAK", &data
[10], 1);
607 JsonSaveBufAsHexCompact(root
, "$.Card.ATQA", &data
[11], 2);
608 uint8_t datslen
= data
[13];
610 JsonSaveBufAsHexCompact(root
, "$.Card.ATS", &data
[14], datslen
);
612 uint8_t dvdata
[4][0xE][24 + 1] = {{{0}}};
613 memcpy(dvdata
, &data
[14 + datslen
], 4 * 0xE * (24 + 1));
615 for (int i
= 0; i
< (int)datalen
; i
++) {
616 char path
[PATH_MAX_LENGTH
] = {0};
618 if (dvdata
[0][i
][0]) {
619 memset(path
, 0x00, sizeof(path
));
620 sprintf(path
, "$.DES.%d.Key", i
);
621 JsonSaveBufAsHexCompact(root
, path
, &dvdata
[0][i
][1], 8);
624 if (dvdata
[1][i
][0]) {
625 memset(path
, 0x00, sizeof(path
));
626 sprintf(path
, "$.3DES.%d.Key", i
);
627 JsonSaveBufAsHexCompact(root
, path
, &dvdata
[1][i
][1], 16);
629 if (dvdata
[2][i
][0]) {
630 memset(path
, 0x00, sizeof(path
));
631 sprintf(path
, "$.AES.%d.Key", i
);
632 JsonSaveBufAsHexCompact(root
, path
, &dvdata
[2][i
][1], 16);
634 if (dvdata
[3][i
][0]) {
635 memset(path
, 0x00, sizeof(path
));
636 sprintf(path
, "$.K3KDES.%d.Key", i
);
637 JsonSaveBufAsHexCompact(root
, path
, &dvdata
[3][i
][1], 24);
653 int res
= json_dump_file(root
, fileName
, JSON_INDENT(2));
655 PrintAndLogEx(FAILED
, "error: can't save the file: " _YELLOW_("%s"), fileName
);
661 PrintAndLogEx(SUCCESS
, "saved to json file " _YELLOW_("%s"), fileName
);
669 int saveFileJSONroot(const char *preferredName
, void *root
, size_t flags
, bool verbose
) {
670 return saveFileJSONrootEx(preferredName
, root
, flags
, verbose
, false);
672 int saveFileJSONrootEx(const char *preferredName
, void *root
, size_t flags
, bool verbose
, bool overwrite
) {
676 char *filename
= NULL
;
678 filename
= filenamemcopy(preferredName
, ".json");
680 filename
= newfilenamemcopy(preferredName
, ".json");
682 if (filename
== NULL
)
685 int res
= json_dump_file(root
, filename
, flags
);
689 PrintAndLogEx(SUCCESS
, "saved to json file " _YELLOW_("%s"), filename
);
694 PrintAndLogEx(FAILED
, "error: can't save the file: " _YELLOW_("%s"), filename
);
700 int saveFileWAVE(const char *preferredName
, int *data
, size_t datalen
) {
702 if (data
== NULL
) return PM3_EINVARG
;
703 char *fileName
= newfilenamemcopy(preferredName
, ".wav");
704 if (fileName
== NULL
) return PM3_EMALLOC
;
705 int retval
= PM3_SUCCESS
;
707 struct wave_info_t wave_info
= {
709 .filesize
= sizeof(wave_info
) - sizeof(wave_info
.signature
) - sizeof(wave_info
.filesize
) + datalen
,
711 .format
.tag
= "fmt ",
712 .format
.size
= sizeof(wave_info
.format
) - sizeof(wave_info
.format
.tag
) - sizeof(wave_info
.format
.size
),
713 .format
.codec
= 1, // PCM
714 .format
.nb_channel
= 1,
715 .format
.sample_per_sec
= 125000, // TODO update for other tag types
716 .format
.byte_per_sec
= 125000, // TODO update for other tag types
717 .format
.block_align
= 1,
718 .format
.bit_per_sample
= 8,
719 .audio_data
.tag
= "data",
720 .audio_data
.size
= datalen
,
723 FILE *wave_file
= fopen(fileName
, "wb");
725 PrintAndLogEx(WARNING
, "file not found or locked. "_YELLOW_("'%s'"), fileName
);
729 fwrite(&wave_info
, sizeof(wave_info
), 1, wave_file
);
730 for (int i
= 0; i
< datalen
; i
++) {
731 uint8_t sample
= data
[i
] + 128;
732 fwrite(&sample
, 1, 1, wave_file
);
736 PrintAndLogEx(SUCCESS
, "saved " _YELLOW_("%zu") " bytes to wave file " _YELLOW_("'%s'"), 2 * datalen
, fileName
);
743 int saveFilePM3(const char *preferredName
, int *data
, size_t datalen
) {
745 if (data
== NULL
) return PM3_EINVARG
;
746 char *fileName
= newfilenamemcopy(preferredName
, ".pm3");
747 if (fileName
== NULL
) return PM3_EMALLOC
;
749 int retval
= PM3_SUCCESS
;
751 FILE *f
= fopen(fileName
, "w");
753 PrintAndLogEx(WARNING
, "file not found or locked. "_YELLOW_("'%s'"), fileName
);
758 for (uint32_t i
= 0; i
< datalen
; i
++)
759 fprintf(f
, "%d\n", data
[i
]);
763 PrintAndLogEx(SUCCESS
, "saved " _YELLOW_("%zu") " bytes to PM3 file " _YELLOW_("'%s'"), datalen
, fileName
);
770 int createMfcKeyDump(const char *preferredName
, uint8_t sectorsCnt
, sector_t
*e_sector
) {
772 if (e_sector
== NULL
) return PM3_EINVARG
;
774 char *fileName
= newfilenamemcopy(preferredName
, ".bin");
775 if (fileName
== NULL
) return PM3_EMALLOC
;
777 FILE *f
= fopen(fileName
, "wb");
779 PrintAndLogEx(WARNING
, "Could not create file " _YELLOW_("%s"), fileName
);
783 PrintAndLogEx(SUCCESS
, "Generating binary key file");
785 uint8_t empty
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
786 uint8_t tmp
[6] = {0, 0, 0, 0, 0, 0};
788 for (int i
= 0; i
< sectorsCnt
; i
++) {
789 if (e_sector
[i
].foundKey
[0])
790 num_to_bytes(e_sector
[i
].Key
[0], sizeof(tmp
), tmp
);
792 memcpy(tmp
, empty
, sizeof(tmp
));
793 fwrite(tmp
, 1, sizeof(tmp
), f
);
796 for (int i
= 0; i
< sectorsCnt
; i
++) {
797 if (e_sector
[i
].foundKey
[0])
798 num_to_bytes(e_sector
[i
].Key
[1], sizeof(tmp
), tmp
);
800 memcpy(tmp
, empty
, sizeof(tmp
));
801 fwrite(tmp
, 1, sizeof(tmp
), f
);
806 PrintAndLogEx(SUCCESS
, "Found keys have been dumped to " _YELLOW_("%s"), fileName
);
807 PrintAndLogEx(INFO
, "FYI! --> " _YELLOW_("0xFFFFFFFFFFFF") " <-- has been inserted for unknown keys where " _YELLOW_("res") " is " _YELLOW_("0"));
812 int loadFile(const char *preferredName
, const char *suffix
, void *data
, size_t maxdatalen
, size_t *datalen
) {
814 if (data
== NULL
) return 1;
815 char *fileName
= filenamemcopy(preferredName
, suffix
);
816 if (fileName
== NULL
) return PM3_EINVARG
;
818 int retval
= PM3_SUCCESS
;
820 FILE *f
= fopen(fileName
, "rb");
822 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", fileName
);
827 // get filesize in order to malloc memory
828 fseek(f
, 0, SEEK_END
);
829 long fsize
= ftell(f
);
830 fseek(f
, 0, SEEK_SET
);
833 PrintAndLogEx(FAILED
, "error, when getting filesize");
838 uint8_t *dump
= calloc(fsize
, sizeof(uint8_t));
840 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
841 retval
= PM3_EMALLOC
;
845 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
847 if (bytes_read
!= fsize
) {
848 PrintAndLogEx(FAILED
, "error, bytes read mismatch file size");
854 if (bytes_read
> maxdatalen
) {
855 PrintAndLogEx(WARNING
, "Warning, bytes read exceed calling array limit. Max bytes is %zu bytes", maxdatalen
);
856 bytes_read
= maxdatalen
;
859 memcpy((data
), dump
, bytes_read
);
862 PrintAndLogEx(SUCCESS
, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read
, fileName
);
864 *datalen
= bytes_read
;
872 int loadFile_safe(const char *preferredName
, const char *suffix
, void **pdata
, size_t *datalen
) {
873 return loadFile_safeEx(preferredName
, suffix
, pdata
, datalen
, true);
875 int loadFile_safeEx(const char *preferredName
, const char *suffix
, void **pdata
, size_t *datalen
, bool verbose
) {
878 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, suffix
, false);
879 if (res
!= PM3_SUCCESS
) {
883 FILE *f
= fopen(path
, "rb");
885 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", path
);
891 // get filesize in order to malloc memory
892 fseek(f
, 0, SEEK_END
);
893 long fsize
= ftell(f
);
894 fseek(f
, 0, SEEK_SET
);
897 PrintAndLogEx(FAILED
, "error, when getting filesize");
902 *pdata
= calloc(fsize
, sizeof(uint8_t));
904 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
909 size_t bytes_read
= fread(*pdata
, 1, fsize
, f
);
913 if (bytes_read
!= fsize
) {
914 PrintAndLogEx(FAILED
, "error, bytes read mismatch file size");
919 *datalen
= bytes_read
;
922 PrintAndLogEx(SUCCESS
, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read
, preferredName
);
926 int loadFileEML(const char *preferredName
, void *data
, size_t *datalen
) {
928 if (data
== NULL
) return PM3_EINVARG
;
930 char *fileName
= filenamemcopy(preferredName
, ".eml");
931 if (fileName
== NULL
) return PM3_EMALLOC
;
934 int retval
= PM3_SUCCESS
, hexlen
= 0;
936 FILE *f
= fopen(fileName
, "r");
938 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", fileName
);
943 // 128 + 2 newline chars + 1 null terminator
945 memset(line
, 0, sizeof(line
));
946 uint8_t buf
[64] = {0x00};
948 uint8_t *udata
= (uint8_t *)data
;
952 memset(line
, 0, sizeof(line
));
954 if (fgets(line
, sizeof(line
), f
) == NULL
) {
959 PrintAndLogEx(FAILED
, "File reading error.");
967 strcleanrn(line
, sizeof(line
));
969 int res
= param_gethex_to_eol(line
, 0, buf
, sizeof(buf
), &hexlen
);
971 memcpy(udata
+ counter
, buf
, hexlen
);
978 PrintAndLogEx(SUCCESS
, "loaded " _YELLOW_("%zu") " bytes from text file " _YELLOW_("%s"), counter
, fileName
);
987 int loadFileEML_safe(const char *preferredName
, void **pdata
, size_t *datalen
) {
989 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, "", false);
990 if (res
!= PM3_SUCCESS
) {
994 FILE *f
= fopen(path
, "r");
996 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", path
);
1002 // get filesize in order to malloc memory
1003 fseek(f
, 0, SEEK_END
);
1004 long fsize
= ftell(f
);
1005 fseek(f
, 0, SEEK_SET
);
1008 PrintAndLogEx(FAILED
, "error, when getting filesize");
1013 *pdata
= calloc(fsize
, sizeof(uint8_t));
1015 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
1020 // 128 + 2 newline chars + 1 null terminator
1022 memset(line
, 0, sizeof(line
));
1023 uint8_t buf
[64] = {0x00};
1025 int retval
= PM3_SUCCESS
, hexlen
= 0;
1027 uint8_t *tmp
= (uint8_t *)*pdata
;
1031 memset(line
, 0, sizeof(line
));
1033 if (fgets(line
, sizeof(line
), f
) == NULL
) {
1038 PrintAndLogEx(FAILED
, "File reading error.");
1045 strcleanrn(line
, sizeof(line
));
1047 res
= param_gethex_to_eol(line
, 0, buf
, sizeof(buf
), &hexlen
);
1049 memcpy(tmp
+ counter
, buf
, hexlen
);
1056 PrintAndLogEx(SUCCESS
, "loaded " _YELLOW_("%zu") " bytes from text file " _YELLOW_("%s"), counter
, preferredName
);
1059 uint8_t *newdump
= realloc(*pdata
, counter
);
1060 if (newdump
== NULL
) {
1073 int loadFileJSON(const char *preferredName
, void *data
, size_t maxdatalen
, size_t *datalen
, void (*callback
)(json_t
*)) {
1074 return loadFileJSONex(preferredName
, data
, maxdatalen
, datalen
, true, callback
);
1076 int loadFileJSONex(const char *preferredName
, void *data
, size_t maxdatalen
, size_t *datalen
, bool verbose
, void (*callback
)(json_t
*)) {
1078 if (data
== NULL
) return PM3_EINVARG
;
1081 int retval
= PM3_SUCCESS
;
1084 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, ".json", false);
1085 if (res
!= PM3_SUCCESS
) {
1090 json_t
*root
= json_load_file(path
, 0, &error
);
1092 PrintAndLogEx(SUCCESS
, "loaded from JSON file " _YELLOW_("%s"), path
);
1097 PrintAndLogEx(ERR
, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", preferredName
, error
.line
, error
.text
);
1102 if (!json_is_object(root
)) {
1103 PrintAndLogEx(ERR
, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName
);
1108 uint8_t *udata
= (uint8_t *)data
;
1109 char ctype
[100] = {0};
1110 JsonLoadStr(root
, "$.FileType", ctype
);
1112 if (!strcmp(ctype
, "raw")) {
1113 JsonLoadBufAsHex(root
, "$.raw", udata
, maxdatalen
, datalen
);
1116 if (!strcmp(ctype
, "mfcard")) {
1118 for (int i
= 0; i
< 256; i
++) {
1119 if (sptr
+ 16 > maxdatalen
) {
1120 retval
= PM3_EMALLOC
;
1124 char blocks
[30] = {0};
1125 sprintf(blocks
, "$.blocks.%d", i
);
1128 JsonLoadBufAsHex(root
, blocks
, &udata
[sptr
], 16, &len
);
1138 if (!strcmp(ctype
, "mfu")) {
1140 for (int i
= 0; i
< 256; i
++) {
1141 if (sptr
+ 4 > maxdatalen
) {
1142 retval
= PM3_EMALLOC
;
1146 char blocks
[30] = {0};
1147 sprintf(blocks
, "$.blocks.%d", i
);
1150 JsonLoadBufAsHex(root
, blocks
, &udata
[sptr
], 4, &len
);
1160 if (!strcmp(ctype
, "hitag")) {
1162 for (size_t i
= 0; i
< (maxdatalen
/ 4); i
++) {
1163 if (sptr
+ 4 > maxdatalen
) {
1164 retval
= PM3_EMALLOC
;
1168 char blocks
[30] = {0};
1169 sprintf(blocks
, "$.blocks.%zu", i
);
1172 JsonLoadBufAsHex(root
, blocks
, &udata
[sptr
], 4, &len
);
1182 if (!strcmp(ctype
, "iclass")) {
1184 for (size_t i
= 0; i
< (maxdatalen
/ 8); i
++) {
1185 if (sptr
+ 8 > maxdatalen
) {
1186 retval
= PM3_EMALLOC
;
1190 char blocks
[30] = {0};
1191 sprintf(blocks
, "$.blocks.%zu", i
);
1194 JsonLoadBufAsHex(root
, blocks
, &udata
[sptr
], 8, &len
);
1203 if (!strcmp(ctype
, "t55x7")) {
1205 for (size_t i
= 0; i
< (maxdatalen
/ 4); i
++) {
1206 if (sptr
+ 4 > maxdatalen
) {
1207 retval
= PM3_EMALLOC
;
1211 char blocks
[30] = {0};
1212 sprintf(blocks
, "$.blocks.%zu", i
);
1215 JsonLoadBufAsHex(root
, blocks
, &udata
[sptr
], 4, &len
);
1224 if (!strcmp(ctype
, "EM4X50")) {
1226 for (size_t i
= 0; i
< (maxdatalen
/ 4); i
++) {
1227 if (sptr
+ 4 > maxdatalen
) {
1228 retval
= PM3_EMALLOC
;
1232 char blocks
[30] = {0};
1233 sprintf(blocks
, "$.blocks.%zu", i
);
1236 JsonLoadBufAsHex(root
, blocks
, &udata
[sptr
], 4, &len
);
1245 if (!strcmp(ctype
, "15693")) {
1246 JsonLoadBufAsHex(root
, "$.raw", udata
, maxdatalen
, datalen
);
1251 if (callback
!= NULL
) {
1259 int loadFileJSONroot(const char *preferredName
, void **proot
, bool verbose
) {
1261 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, ".json", false);
1262 if (res
!= PM3_SUCCESS
) {
1267 json_t
*root
= json_load_file(path
, 0, &error
);
1269 PrintAndLogEx(SUCCESS
, "loaded from JSON file " _YELLOW_("%s"), path
);
1273 int retval
= PM3_SUCCESS
;
1275 PrintAndLogEx(ERR
, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", preferredName
, error
.line
, error
.text
);
1280 if (!json_is_object(root
)) {
1281 PrintAndLogEx(ERR
, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName
);
1294 int loadFileDICTIONARY(const char *preferredName
, void *data
, size_t *datalen
, uint8_t keylen
, uint32_t *keycnt
) {
1296 // mifare == 6 bytes
1297 // mf plus == 16 bytes
1298 // iclass == 8 bytes
1299 // default to 6 bytes.
1300 if (keylen
!= 4 && keylen
!= 6 && keylen
!= 8 && keylen
!= 16) {
1304 return loadFileDICTIONARYEx(preferredName
, data
, 0, datalen
, keylen
, keycnt
, 0, NULL
, true);
1307 int loadFileDICTIONARYEx(const char *preferredName
, void *data
, size_t maxdatalen
, size_t *datalen
, uint8_t keylen
, uint32_t *keycnt
,
1308 size_t startFilePosition
, size_t *endFilePosition
, bool verbose
) {
1310 if (data
== NULL
) return PM3_EINVARG
;
1312 if (endFilePosition
)
1313 *endFilePosition
= 0;
1316 if (searchFile(&path
, DICTIONARIES_SUBDIR
, preferredName
, ".dic", false) != PM3_SUCCESS
)
1319 // double up since its chars
1323 uint32_t vkeycnt
= 0;
1325 int retval
= PM3_SUCCESS
;
1327 FILE *f
= fopen(path
, "r");
1329 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", path
);
1334 if (startFilePosition
) {
1335 if (fseek(f
, startFilePosition
, SEEK_SET
) < 0) {
1342 uint8_t *udata
= (uint8_t *)data
;
1346 long filepos
= ftell(f
);
1348 if (!fgets(line
, sizeof(line
), f
)) {
1349 if (endFilePosition
)
1350 *endFilePosition
= 0;
1354 // add null terminator
1357 // smaller keys than expected is skipped
1358 if (strlen(line
) < keylen
)
1361 // The line start with # is comment, skip
1365 if (!CheckStringIsHEXValue(line
))
1368 // cant store more data
1369 if (maxdatalen
&& (counter
+ (keylen
>> 1) > maxdatalen
)) {
1371 if (endFilePosition
)
1372 *endFilePosition
= filepos
;
1376 if (hex_to_bytes(line
, udata
+ counter
, keylen
>> 1) != (keylen
>> 1))
1380 memset(line
, 0, sizeof(line
));
1381 counter
+= (keylen
>> 1);
1385 PrintAndLogEx(SUCCESS
, "loaded " _GREEN_("%2d") " keys from dictionary file " _YELLOW_("%s"), vkeycnt
, path
);
1396 int loadFileDICTIONARY_safe(const char *preferredName
, void **pdata
, uint8_t keylen
, uint32_t *keycnt
) {
1398 int retval
= PM3_SUCCESS
;
1401 if (searchFile(&path
, DICTIONARIES_SUBDIR
, preferredName
, ".dic", false) != PM3_SUCCESS
)
1405 // mifare == 6 bytes
1406 // mf plus == 16 bytes
1407 // iclass == 8 bytes
1408 // default to 6 bytes.
1409 if (keylen
!= 4 && keylen
!= 6 && keylen
!= 8 && keylen
!= 16) {
1414 size_t block_size
= 10 * keylen
;
1416 // double up since its chars
1421 // allocate some space for the dictionary
1422 *pdata
= calloc(block_size
, sizeof(uint8_t));
1423 if (*pdata
== NULL
) {
1427 mem_size
= block_size
;
1429 FILE *f
= fopen(path
, "r");
1431 PrintAndLogEx(WARNING
, "file not found or locked. '" _YELLOW_("%s")"'", path
);
1437 while (fgets(line
, sizeof(line
), f
)) {
1439 // check if we have enough space (if not allocate more)
1440 if ((*keycnt
* (keylen
>> 1)) >= mem_size
) {
1442 mem_size
+= block_size
;
1443 *pdata
= realloc(*pdata
, mem_size
);
1445 if (*pdata
== NULL
) {
1450 memset((uint8_t *)*pdata
+ (mem_size
- block_size
), 0, block_size
);
1454 // add null terminator
1457 // smaller keys than expected is skipped
1458 if (strlen(line
) < keylen
)
1461 // The line start with # is comment, skip
1465 if (!CheckStringIsHEXValue(line
))
1468 uint64_t key
= strtoull(line
, NULL
, 16);
1470 num_to_bytes(key
, keylen
>> 1, (uint8_t *)*pdata
+ (*keycnt
* (keylen
>> 1)));
1474 memset(line
, 0, sizeof(line
));
1477 PrintAndLogEx(SUCCESS
, "loaded " _GREEN_("%2d") " keys from dictionary file " _YELLOW_("%s"), *keycnt
, path
);
1484 mfu_df_e
detect_mfu_dump_format(uint8_t **dump
, size_t *dumplen
, bool verbose
) {
1486 mfu_df_e retval
= MFU_DF_UNKNOWN
;
1491 mfu_dump_t
*new = (mfu_dump_t
*)*dump
;
1492 bcc0
= ct
^ new->data
[0] ^ new->data
[1] ^ new->data
[2];
1493 bcc1
= new->data
[4] ^ new->data
[5] ^ new->data
[6] ^ new->data
[7];
1494 if (bcc0
== new->data
[3] && bcc1
== new->data
[8]) {
1495 retval
= MFU_DF_NEWBIN
;
1499 if (retval
== MFU_DF_UNKNOWN
) {
1500 old_mfu_dump_t
*old
= (old_mfu_dump_t
*)*dump
;
1501 bcc0
= ct
^ old
->data
[0] ^ old
->data
[1] ^ old
->data
[2];
1502 bcc1
= old
->data
[4] ^ old
->data
[5] ^ old
->data
[6] ^ old
->data
[7];
1503 if (bcc0
== old
->data
[3] && bcc1
== old
->data
[8]) {
1504 retval
= MFU_DF_OLDBIN
;
1509 if (retval
== MFU_DF_UNKNOWN
) {
1510 uint8_t *plain
= *dump
;
1511 bcc0
= ct
^ plain
[0] ^ plain
[1] ^ plain
[2];
1512 bcc1
= plain
[4] ^ plain
[5] ^ plain
[6] ^ plain
[7];
1513 if ((bcc0
== plain
[3]) && (bcc1
== plain
[8])) {
1514 retval
= MFU_DF_PLAINBIN
;
1521 PrintAndLogEx(INFO
, "detected " _GREEN_("new") " mfu dump format");
1524 PrintAndLogEx(INFO
, "detected " _GREEN_("old") " mfu dump format");
1526 case MFU_DF_PLAINBIN
:
1527 PrintAndLogEx(INFO
, "detected " _GREEN_("plain") " mfu dump format");
1529 case MFU_DF_UNKNOWN
:
1530 PrintAndLogEx(WARNING
, "failed to detected mfu dump format");
1537 static int convert_plain_mfu_dump(uint8_t **dump
, size_t *dumplen
, bool verbose
) {
1539 mfu_dump_t
*mfu
= (mfu_dump_t
*) calloc(sizeof(mfu_dump_t
), sizeof(uint8_t));
1544 memcpy(mfu
->data
, *dump
, *dumplen
);
1546 mfu
->pages
= *dumplen
/ 4 - 1;
1549 PrintAndLogEx(SUCCESS
, "plain mfu dump format was converted to " _GREEN_("%d") " blocks", mfu
->pages
+ 1);
1552 *dump
= (uint8_t *)mfu
;
1553 *dumplen
+= MFU_DUMP_PREFIX_LENGTH
;
1557 static int convert_old_mfu_dump(uint8_t **dump
, size_t *dumplen
, bool verbose
) {
1565 uint8_t signature[32];
1567 } PACKED old_mfu_dump_t;
1570 // convert old format
1571 old_mfu_dump_t
*old_mfu_dump
= (old_mfu_dump_t
*)*dump
;
1573 size_t old_data_len
= *dumplen
- OLD_MFU_DUMP_PREFIX_LENGTH
;
1574 size_t new_dump_len
= old_data_len
+ MFU_DUMP_PREFIX_LENGTH
;
1576 mfu_dump_t
*mfu_dump
= (mfu_dump_t
*) calloc(sizeof(mfu_dump_t
), sizeof(uint8_t));
1577 if (mfu_dump
== NULL
) {
1581 memcpy(mfu_dump
->version
, old_mfu_dump
->version
, sizeof(mfu_dump
->version
));
1582 memcpy(mfu_dump
->tbo
, old_mfu_dump
->tbo
, sizeof(mfu_dump
->tbo
));
1583 memcpy(mfu_dump
->signature
, old_mfu_dump
->signature
, sizeof(mfu_dump
->signature
));
1585 mfu_dump
->tbo1
[0] = old_mfu_dump
->tbo1
[0];
1587 for (int i
= 0; i
< 3; i
++) {
1588 mfu_dump
->counter_tearing
[i
][3] = old_mfu_dump
->tearing
[i
];
1591 memcpy(mfu_dump
->data
, old_mfu_dump
->data
, sizeof(mfu_dump
->data
));
1592 mfu_dump
->pages
= old_data_len
/ 4 - 1;
1594 // Add PACK to last block of memory.
1595 memcpy(mfu_dump
->data
+ (mfu_dump
->pages
* 4 + MFU_DUMP_PREFIX_LENGTH
), old_mfu_dump
->pack
, 2);
1598 PrintAndLogEx(SUCCESS
, "old mfu dump format was converted to " _GREEN_("%d") " blocks", mfu_dump
->pages
+ 1);
1602 *dump
= (uint8_t *)mfu_dump
;
1603 *dumplen
= new_dump_len
;
1607 int convert_mfu_dump_format(uint8_t **dump
, size_t *dumplen
, bool verbose
) {
1609 if (!dump
|| !dumplen
|| *dumplen
< OLD_MFU_DUMP_PREFIX_LENGTH
) {
1613 mfu_df_e res
= detect_mfu_dump_format(dump
, dumplen
, verbose
);
1619 return convert_old_mfu_dump(dump
, dumplen
, verbose
);
1620 case MFU_DF_PLAINBIN
:
1621 return convert_plain_mfu_dump(dump
, dumplen
, verbose
);
1622 case MFU_DF_UNKNOWN
:
1628 static int filelist(const char *path
, const char *ext
, uint8_t last
, bool tentative
, uint8_t indent
, uint16_t strip
) {
1629 struct dirent
**namelist
;
1632 n
= scandir(path
, &namelist
, NULL
, alphasort
);
1635 if (tentative
== false) {
1637 for (uint8_t j
= 0; j
< indent
; j
++) {
1638 PrintAndLogEx(NORMAL
, "%s " NOLF
, ((last
>> j
) & 1) ? " " : "│");
1640 PrintAndLogEx(NORMAL
, "%s── "_GREEN_("%s"), last
? "└" : "├", &path
[strip
]);
1645 for (uint8_t j
= 0; j
< indent
; j
++) {
1646 PrintAndLogEx(NORMAL
, "%s " NOLF
, ((last
>> j
) & 1) ? " " : "│");
1649 PrintAndLogEx(NORMAL
, "%s── "_GREEN_("%s"), last
? "└" : "├", &path
[strip
]);
1651 for (uint16_t i
= 0; i
< n
; i
++) {
1653 char tmp_fullpath
[1024] = {0};
1654 strncat(tmp_fullpath
, path
, sizeof(tmp_fullpath
) - 1);
1655 tmp_fullpath
[1023] = 0x00;
1656 strncat(tmp_fullpath
, namelist
[i
]->d_name
, strlen(tmp_fullpath
) - 1);
1658 if (is_directory(tmp_fullpath
)) {
1661 if (strcmp(namelist
[i
]->d_name
, ".") == 0 || strcmp(namelist
[i
]->d_name
, "..") == 0)
1664 snprintf(newpath
, sizeof(newpath
), "%s", path
);
1665 strncat(newpath
, namelist
[i
]->d_name
, sizeof(newpath
) - strlen(newpath
) - 1);
1666 strncat(newpath
, "/", sizeof(newpath
) - strlen(newpath
) - 1);
1668 filelist(newpath
, ext
, last
+ ((i
== n
- 1) << (indent
+ 1)), tentative
, indent
+ 1, strlen(path
));
1671 if ((ext
== NULL
) || ((str_endswith(namelist
[i
]->d_name
, ext
)))) {
1673 for (uint8_t j
= 0; j
< indent
+ 1; j
++) {
1674 PrintAndLogEx(NORMAL
, "%s " NOLF
, ((last
>> j
) & 1) ? " " : "│");
1676 PrintAndLogEx(NORMAL
, "%s── %-21s", i
== n
- 1 ? "└" : "├", namelist
[i
]->d_name
);
1685 int searchAndList(const char *pm3dir
, const char *ext
) {
1686 // display in same order as searched by searchFile
1687 // try pm3 dirs in current workdir (dev mode)
1688 if (get_my_executable_directory() != NULL
) {
1689 char script_directory_path
[strlen(get_my_executable_directory()) + strlen(pm3dir
) + 1];
1690 strcpy(script_directory_path
, get_my_executable_directory());
1691 strcat(script_directory_path
, pm3dir
);
1692 filelist(script_directory_path
, ext
, false, true, 0, 0);
1694 // try pm3 dirs in user .proxmark3 (user mode)
1695 const char *user_path
= get_my_user_directory();
1696 if (user_path
!= NULL
) {
1697 char script_directory_path
[strlen(user_path
) + strlen(PM3_USER_DIRECTORY
) + strlen(pm3dir
) + 1];
1698 strcpy(script_directory_path
, user_path
);
1699 strcat(script_directory_path
, PM3_USER_DIRECTORY
);
1700 strcat(script_directory_path
, pm3dir
);
1701 filelist(script_directory_path
, ext
, false, false, 0, 0);
1703 // try pm3 dirs in pm3 installation dir (install mode)
1704 const char *exec_path
= get_my_executable_directory();
1705 if (exec_path
!= NULL
) {
1706 char script_directory_path
[strlen(exec_path
) + strlen(PM3_SHARE_RELPATH
) + strlen(pm3dir
) + 1];
1707 strcpy(script_directory_path
, exec_path
);
1708 strcat(script_directory_path
, PM3_SHARE_RELPATH
);
1709 strcat(script_directory_path
, pm3dir
);
1710 filelist(script_directory_path
, ext
, true, false, 0, 0);
1715 static int searchFinalFile(char **foundpath
, const char *pm3dir
, const char *searchname
, bool silent
) {
1716 if ((foundpath
== NULL
) || (pm3dir
== NULL
) || (searchname
== NULL
)) return PM3_ESOFT
;
1717 // explicit absolute (/) or relative path (./) => try only to match it directly
1718 char *filename
= calloc(strlen(searchname
) + 1, sizeof(char));
1719 if (filename
== NULL
) return PM3_EMALLOC
;
1720 strcpy(filename
, searchname
);
1721 if ((g_debugMode
== 2) && (!silent
)) {
1722 PrintAndLogEx(INFO
, "Searching %s", filename
);
1724 if (((strlen(filename
) > 1) && (filename
[0] == '/')) ||
1725 ((strlen(filename
) > 2) && (filename
[0] == '.') && (filename
[1] == '/'))) {
1726 if (fileExists(filename
)) {
1727 *foundpath
= filename
;
1728 if ((g_debugMode
== 2) && (!silent
)) {
1729 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
1738 // try implicit relative path
1740 if (fileExists(filename
)) {
1741 *foundpath
= filename
;
1742 if ((g_debugMode
== 2) && (!silent
)) {
1743 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
1748 // try pm3 dirs in user .proxmark3 (user mode)
1749 const char *user_path
= get_my_user_directory();
1750 if (user_path
!= NULL
) {
1751 char *path
= calloc(strlen(user_path
) + strlen(PM3_USER_DIRECTORY
) + strlen(pm3dir
) + strlen(filename
) + 1, sizeof(char));
1754 strcpy(path
, user_path
);
1755 strcat(path
, PM3_USER_DIRECTORY
);
1756 strcat(path
, pm3dir
);
1757 strcat(path
, filename
);
1758 if ((g_debugMode
== 2) && (!silent
)) {
1759 PrintAndLogEx(INFO
, "Searching %s", path
);
1761 if (fileExists(path
)) {
1764 if ((g_debugMode
== 2) && (!silent
)) {
1765 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
1772 // try pm3 dirs in current client workdir (dev mode)
1773 const char *exec_path
= get_my_executable_directory();
1774 if ((exec_path
!= NULL
) &&
1775 ((strcmp(DICTIONARIES_SUBDIR
, pm3dir
) == 0) ||
1776 (strcmp(LUA_LIBRARIES_SUBDIR
, pm3dir
) == 0) ||
1777 (strcmp(LUA_SCRIPTS_SUBDIR
, pm3dir
) == 0) ||
1778 (strcmp(CMD_SCRIPTS_SUBDIR
, pm3dir
) == 0) ||
1779 (strcmp(PYTHON_SCRIPTS_SUBDIR
, pm3dir
) == 0) ||
1780 (strcmp(RESOURCES_SUBDIR
, pm3dir
) == 0))) {
1781 char *path
= calloc(strlen(exec_path
) + strlen(pm3dir
) + strlen(filename
) + 1, sizeof(char));
1784 strcpy(path
, exec_path
);
1785 strcat(path
, pm3dir
);
1786 strcat(path
, filename
);
1787 if ((g_debugMode
== 2) && (!silent
)) {
1788 PrintAndLogEx(INFO
, "Searching %s", path
);
1790 if (fileExists(path
)) {
1793 if ((g_debugMode
== 2) && (!silent
)) {
1794 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
1801 // try pm3 dirs in current repo workdir (dev mode)
1802 if ((exec_path
!= NULL
) &&
1803 ((strcmp(TRACES_SUBDIR
, pm3dir
) == 0) ||
1804 (strcmp(FIRMWARES_SUBDIR
, pm3dir
) == 0) ||
1805 (strcmp(BOOTROM_SUBDIR
, pm3dir
) == 0) ||
1806 (strcmp(FULLIMAGE_SUBDIR
, pm3dir
) == 0))) {
1807 const char *above
= "../";
1808 char *path
= calloc(strlen(exec_path
) + strlen(above
) + strlen(pm3dir
) + strlen(filename
) + 1, sizeof(char));
1811 strcpy(path
, exec_path
);
1812 strcat(path
, above
);
1813 strcat(path
, pm3dir
);
1814 strcat(path
, filename
);
1815 if ((g_debugMode
== 2) && (!silent
)) {
1816 PrintAndLogEx(INFO
, "Searching %s", path
);
1818 if (fileExists(path
)) {
1821 if ((g_debugMode
== 2) && (!silent
)) {
1822 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
1829 // try pm3 dirs in pm3 installation dir (install mode)
1830 if (exec_path
!= NULL
) {
1831 char *path
= calloc(strlen(exec_path
) + strlen(PM3_SHARE_RELPATH
) + strlen(pm3dir
) + strlen(filename
) + 1, sizeof(char));
1834 strcpy(path
, exec_path
);
1835 strcat(path
, PM3_SHARE_RELPATH
);
1836 strcat(path
, pm3dir
);
1837 strcat(path
, filename
);
1838 if ((g_debugMode
== 2) && (!silent
)) {
1839 PrintAndLogEx(INFO
, "Searching %s", path
);
1841 if (fileExists(path
)) {
1844 if ((g_debugMode
== 2) && (!silent
)) {
1845 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
1857 int searchFile(char **foundpath
, const char *pm3dir
, const char *searchname
, const char *suffix
, bool silent
) {
1859 if (foundpath
== NULL
)
1862 if (searchname
== NULL
|| strlen(searchname
) == 0)
1865 if (is_directory(searchname
))
1868 char *filename
= filenamemcopy(searchname
, suffix
);
1869 if (filename
== NULL
)
1872 if (strlen(filename
) == 0) {
1876 int res
= searchFinalFile(foundpath
, pm3dir
, filename
, silent
);
1877 if (res
!= PM3_SUCCESS
) {
1878 if ((res
== PM3_EFILE
) && (!silent
))
1879 PrintAndLogEx(FAILED
, "Error - can't find `" _YELLOW_("%s") "`", filename
);