diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index ac6a71242..b1cc0e0c1 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -9,7 +9,7 @@ jobs: - name: Changelog Reminder uses: peterjgrainger/action-changelog-reminder@v1.2.0 with: - changelog_regex: '/CHANGELOG.md' + changelog_regex: 'CHANGELOG.md' customPrMessage: 'You are welcome to add an entry to the CHANGELOG.md as well' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ff678161..ef2cf914c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 PM3 client to honor the preferences dump/trace paths. experimental support (@iceman1001) + - Added the possibility to load `.MCT` dump files (@iceman1001) - Changed `lf t55xx dump --ns` - now supports `no save` of memory (@iceman1001) - Fixed the USB enumeration process (@wh201906) - Fixed `hf mf rdsc` - now correctly gets size in bytes when sector is larger than 32 (@iceman1001) @@ -50,6 +52,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf legic einfo` - views emulator menory (@0xdeb) - Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb) - Now `script run hf_mf_ultimatecard.lua -u` supports 10bytes UID (@alejandro12120) + - Update documentation for installation on macOS with MacPorts (@linuxgemini) ## [Nitride.4.16191][2023-01-29] - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 8a6049d3c..bb9c7635e 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -85,6 +85,8 @@ DumpFileType_t getfiletype(const char *filename) { o = JSON; } else if (str_endswith(s, "dic")) { o = DICTIONARY; + } else if (str_endswith(s, "mct")) { + o = MCT; } else { // mfd, trc, trace is binary o = BIN; @@ -112,27 +114,6 @@ int fileExists(const char *filename) { return result == 0; } -/** - * @brief checks if path is file. - * @param filename - * @return - */ -/* -static bool is_regular_file(const char *filename) { -#ifdef _WIN32 - struct _stat st; - if (_stat(filename, &st) == -1) - return false; -#else - struct stat st; -// stat(filename, &st); - if (lstat(filename, &st) == -1) - return false; -#endif - return S_ISREG(st.st_mode) != 0; -} -*/ - /** * @brief checks if path is directory. * @param filename @@ -152,68 +133,6 @@ static bool is_directory(const char *filename) { return S_ISDIR(st.st_mode) != 0; } -/** - * @brief create a new directory. - * @param dirname - * @return - */ -// Not used... -/* -#ifdef _WIN32 -#define make_dir(a) _mkdir(a) -#else -#define make_dir(a) mkdir(a,0755) //note 0755 MUST have leading 0 for octal linux file permissions -#endif -bool create_path(const char *dirname) { - - if (dirname == NULL) // nothing to do - return false; - - if ((strlen(dirname) == 1) && (dirname[0] == '/')) - return true; - - if ((strlen(dirname) == 2) && (dirname[1] == ':')) - return true; - - if (fileExists(dirname) == 0) { - - char *bs = strrchr(dirname, '\\'); - char *fs = strrchr(dirname, '/'); - - if ((bs == NULL) && (fs != NULL)) { - *fs = 0x00; - create_path (dirname); - *fs = '/'; - } - - if ((bs != NULL) && (fs == NULL)) { - *bs = 0x00; - create_path (dirname); - *bs = '\\'; - } - - if ((bs != NULL) && (fs != NULL)) { - if (strlen (bs) > strlen (fs)) { - *fs = 0x00; // No slash - create_path (dirname); - *fs = '/'; - } else { - *bs = 0x00; - create_path (dirname); - *bs = '\\'; - } - - } - - if (make_dir(dirname) != 0) { - PrintAndLogEx(ERR, "could not create directory.... "_RED_("%s"),dirname); - return false; - } - } - return true; -} -*/ - bool setDefaultPath(savePaths_t pathIndex, const char *path) { if (pathIndex < spItemCount) { @@ -262,37 +181,55 @@ static size_t path_size(savePaths_t a) { } char *newfilenamemcopy(const char *preferredName, const char *suffix) { + return newfilenamemcopyEx(preferredName, suffix, spDefault); +} + +char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t e_save_path) { if (preferredName == NULL || suffix == NULL) { return NULL; } uint16_t p_namelen = strlen(preferredName); - if (str_endswith(preferredName, suffix)) + if (str_endswith(preferredName, suffix)) { p_namelen -= strlen(suffix); + } - // 10: room for filenum to ensure new filename - const size_t len = p_namelen + strlen(suffix) + 1 + 10; + int save_path_len = path_size(e_save_path); - int foobar = path_size(spDefault); - (void) foobar; + // 1: null terminator + // 16: room for filenum to ensure new filename + // save_path_len + strlen(PATHSEP): the user preference save paths + const size_t len = p_namelen + strlen(suffix) + 1 + 16 + save_path_len + strlen(PATHSEP); char *fileName = (char *) calloc(len, sizeof(uint8_t)); if (fileName == NULL) { return NULL; } + char *pfn = fileName; + + // user preference save paths + if (save_path_len) { + snprintf(pfn, save_path_len + strlen(PATHSEP) + 1, "%s%s", g_session.defaultPaths[e_save_path], PATHSEP); + pfn += save_path_len + strlen(PATHSEP); + } + int num = 1; - snprintf(fileName, len, "%.*s%s", p_namelen, preferredName, suffix); + // modify filename + snprintf(pfn, len, "%.*s%s", p_namelen, preferredName, suffix); + + // check complete path/filename if exists while (fileExists(fileName)) { - snprintf(fileName, len, "%.*s-%d%s", p_namelen, preferredName, num, suffix); + // modify filename + snprintf(pfn, len, "%.*s-%03d%s", p_namelen, preferredName, num, suffix); num++; } - PrintAndLogEx(INFO, "FILE PATH: %s", fileName); return fileName; } +// --------- SAVE FILES int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) { if (data == NULL || datalen == 0) { @@ -321,13 +258,14 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si return PM3_SUCCESS; } +// dump file int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) { if (data == NULL || datalen == 0) { return PM3_EINVARG; } - char *fileName = newfilenamemcopy(preferredName, ".eml"); + char *fileName = newfilenamemcopyEx(preferredName, ".eml", spDump); if (fileName == NULL) { return PM3_EMALLOC; } @@ -371,16 +309,19 @@ out: return retval; } +// dump file (normally, we also got preference file, etc) int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *)) { - return saveFileJSONex(preferredName, ftype, data, datalen, true, callback); + return saveFileJSONex(preferredName, ftype, data, datalen, true, callback, spDump); } -int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) { +int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *), savePaths_t e_save_path) { + if (ftype != jsfCustom) { if (data == NULL || datalen == 0) { return PM3_EINVARG; } + } - char *fileName = newfilenamemcopy(preferredName, ".json"); + char *fileName = newfilenamemcopyEx(preferredName, ".json", e_save_path); if (fileName == NULL) { return PM3_EMALLOC; } @@ -719,7 +660,7 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool if (overwrite) filename = filenamemcopy(preferredName, ".json"); else - filename = newfilenamemcopy(preferredName, ".json"); + filename = newfilenamemcopyEx(preferredName, ".json", spDump); if (filename == NULL) return PM3_EMALLOC; @@ -739,13 +680,14 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool return PM3_EFILE; } +// wave file of trace, int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) { if (data == NULL || datalen == 0) { return PM3_EINVARG; } - char *fileName = newfilenamemcopy(preferredName, ".wav"); + char *fileName = newfilenamemcopyEx(preferredName, ".wav", spTrace); if (fileName == NULL) { return PM3_EMALLOC; } @@ -791,13 +733,14 @@ out: return retval; } +// Signal trace file, PM3 int saveFilePM3(const char *preferredName, int *data, size_t datalen) { if (data == NULL || datalen == 0) { return PM3_EINVARG; } - char *fileName = newfilenamemcopy(preferredName, ".pm3"); + char *fileName = newfilenamemcopyEx(preferredName, ".pm3", spTrace); if (fileName == NULL) { return PM3_EMALLOC; } @@ -824,11 +767,12 @@ out: return retval; } +// key file dump int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) { if (e_sector == NULL) return PM3_EINVARG; - char *fileName = newfilenamemcopy(preferredName, ".bin"); + char *fileName = newfilenamemcopyEx(preferredName, ".bin", spDump); if (fileName == NULL) return PM3_EMALLOC; FILE *f = fopen(fileName, "wb"); @@ -866,66 +810,7 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_ return PM3_SUCCESS; } -int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) { - - if (data == NULL) return 1; - char *fileName = filenamemcopy(preferredName, suffix); - if (fileName == NULL) return PM3_EINVARG; - - int retval = PM3_SUCCESS; - - FILE *f = fopen(fileName, "rb"); - if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName); - free(fileName); - return PM3_EFILE; - } - - // get filesize in order to malloc memory - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - - if (fsize <= 0) { - PrintAndLogEx(FAILED, "error, when getting filesize"); - retval = PM3_EFILE; - goto out; - } - - uint8_t *dump = calloc(fsize, sizeof(uint8_t)); - if (!dump) { - PrintAndLogEx(FAILED, "error, cannot allocate memory"); - retval = PM3_EMALLOC; - goto out; - } - - size_t bytes_read = fread(dump, 1, fsize, f); - - if (bytes_read != fsize) { - PrintAndLogEx(FAILED, "error, bytes read mismatch file size"); - free(dump); - retval = PM3_EFILE; - goto out; - } - - if (bytes_read > maxdatalen) { - PrintAndLogEx(WARNING, "Warning, bytes read exceed calling array limit. Max bytes is %zu bytes", maxdatalen); - bytes_read = maxdatalen; - } - - memcpy((data), dump, bytes_read); - free(dump); - - PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, fileName); - - *datalen = bytes_read; - -out: - fclose(f); - free(fileName); - return retval; -} - +// --------- LOAD FILES int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) { return loadFile_safeEx(preferredName, suffix, pdata, datalen, true); } @@ -975,72 +860,12 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, *datalen = bytes_read; - if (verbose) + if (verbose) { PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName); + } return PM3_SUCCESS; } -int loadFileEML(const char *preferredName, void *data, size_t *datalen) { - - if (data == NULL) return PM3_EINVARG; - - char *fileName = filenamemcopy(preferredName, ".eml"); - if (fileName == NULL) return PM3_EMALLOC; - - size_t counter = 0; - int retval = PM3_SUCCESS, hexlen = 0; - - FILE *f = fopen(fileName, "r"); - if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName); - retval = PM3_EFILE; - goto out; - } - - // 128 + 2 newline chars + 1 null terminator - char line[131]; - memset(line, 0, sizeof(line)); - uint8_t buf[64] = {0x00}; - - uint8_t *udata = (uint8_t *)data; - - while (!feof(f)) { - - memset(line, 0, sizeof(line)); - - if (fgets(line, sizeof(line), f) == NULL) { - if (feof(f)) - break; - - fclose(f); - PrintAndLogEx(FAILED, "File reading error."); - retval = PM3_EFILE; - goto out; - } - - if (line[0] == '#') - continue; - - strcleanrn(line, sizeof(line)); - - int res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen); - if (res == 0) { - memcpy(udata + counter, buf, hexlen); - counter += hexlen; - } else { - retval = PM3_ESOFT; - } - } - fclose(f); - PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from text file " _YELLOW_("%s"), counter, fileName); - - if (datalen) - *datalen = counter; - -out: - free(fileName); - return retval; -} int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { char *path; int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false); @@ -1127,6 +952,93 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { return retval; } +int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) { + char *path; + int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false); + if (res != PM3_SUCCESS) { + return PM3_EFILE; + } + + FILE *f = fopen(path, "r"); + if (!f) { + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); + free(path); + return PM3_EFILE; + } + free(path); + + // get filesize in order to malloc memory + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + if (fsize <= 0) { + PrintAndLogEx(FAILED, "error, when getting filesize"); + fclose(f); + return PM3_EFILE; + } + + *pdata = calloc(fsize, sizeof(uint8_t)); + if (!*pdata) { + PrintAndLogEx(FAILED, "error, cannot allocate memory"); + fclose(f); + return PM3_EMALLOC; + } + + // 128 + 2 newline chars + 1 null terminator + char line[131]; + memset(line, 0, sizeof(line)); + uint8_t buf[64] = {0x00}; + size_t counter = 0; + int retval = PM3_SUCCESS, hexlen = 0; + + uint8_t *tmp = (uint8_t *)*pdata; + + while (!feof(f)) { + + memset(line, 0, sizeof(line)); + + if (fgets(line, sizeof(line), f) == NULL) { + if (feof(f)) + break; + + fclose(f); + PrintAndLogEx(FAILED, "File reading error."); + return PM3_EFILE; + } + + // skip lines like "+Sector:" + if (line[0] == '+') + continue; + + strcleanrn(line, sizeof(line)); + + res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen); + if (res == 0) { + memcpy(tmp + counter, buf, hexlen); + counter += hexlen; + } else { + retval = PM3_ESOFT; + } + } + fclose(f); + PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from MCT file " _YELLOW_("%s"), counter, preferredName); + + + uint8_t *newdump = realloc(*pdata, counter); + if (newdump == NULL) { + free(*pdata); + return PM3_EMALLOC; + } else { + *pdata = newdump; + } + + if (datalen) + *datalen = counter; + + return retval; +} + int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, void (*callback)(json_t *)) { return loadFileJSONex(preferredName, data, maxdatalen, datalen, true, callback); } @@ -1903,51 +1815,84 @@ int searchAndList(const char *pm3dir, const char *ext) { } static int searchFinalFile(char **foundpath, const char *pm3dir, const char *searchname, bool silent) { - if ((foundpath == NULL) || (pm3dir == NULL) || (searchname == NULL)) return PM3_ESOFT; + + if ((foundpath == NULL) || (pm3dir == NULL) || (searchname == NULL)) { + return PM3_ESOFT; + } + // explicit absolute (/) or relative path (./) => try only to match it directly char *filename = calloc(strlen(searchname) + 1, sizeof(char)); - if (filename == NULL) return PM3_EMALLOC; + if (filename == NULL) { + return PM3_EMALLOC; + } + strcpy(filename, searchname); if ((g_debugMode == 2) && (!silent)) { - PrintAndLogEx(INFO, "Searching %s", filename); + PrintAndLogEx(INFO, "pm3dir...... %s", pm3dir); + PrintAndLogEx(INFO, "Searching... %s", filename); } + + // try implicit relative path + PrintAndLogEx(DEBUG, "Searching implicit relative paths"); + if (fileExists(filename)) { + *foundpath = filename; + if ((g_debugMode == 2) && (!silent)) { + PrintAndLogEx(INFO, "Found %s", *foundpath); + } + return PM3_SUCCESS; + } + if (((strlen(filename) > 1) && (filename[0] == '/')) || ((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) { - if (fileExists(filename)) { - *foundpath = filename; + goto out; + } + + // try the session paths + PrintAndLogEx(DEBUG, "Searching preferences paths"); + for (int i = 0; i < spItemCount; i++) { + + size_t sn = strlen(g_session.defaultPaths[i]) + strlen(filename) + strlen(PATHSEP) + 1; + char *default_path = calloc(sn, sizeof(char)); + if (default_path == NULL) { + goto out; + } + + snprintf(default_path, sn, "%s%s%s", g_session.defaultPaths[i], PATHSEP, filename); + + if ((g_debugMode == 2) && (!silent)) { + PrintAndLogEx(INFO, "Searching %s", default_path); + } + + if (fileExists(default_path)) { + free(filename); + *foundpath = default_path; if ((g_debugMode == 2) && (!silent)) { PrintAndLogEx(INFO, "Found %s", *foundpath); } return PM3_SUCCESS; } else { - goto out; + free(default_path); } } - // else - // try implicit relative path - { - if (fileExists(filename)) { - *foundpath = filename; - if ((g_debugMode == 2) && (!silent)) { - PrintAndLogEx(INFO, "Found %s", *foundpath); - } - return PM3_SUCCESS; - } - } // try pm3 dirs in user .proxmark3 (user mode) + PrintAndLogEx(DEBUG, "Searching user .proxmark3 paths"); const char *user_path = get_my_user_directory(); if (user_path != NULL) { char *path = calloc(strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); - if (path == NULL) + if (path == NULL) { goto out; + } + strcpy(path, user_path); strcat(path, PM3_USER_DIRECTORY); strcat(path, pm3dir); strcat(path, filename); + if ((g_debugMode == 2) && (!silent)) { PrintAndLogEx(INFO, "Searching %s", path); } + if (fileExists(path)) { free(filename); *foundpath = path; @@ -1959,7 +1904,9 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea free(path); } } + // try pm3 dirs in current client workdir (dev mode) + PrintAndLogEx(DEBUG, "Searching current workdir paths"); const char *exec_path = get_my_executable_directory(); if ((exec_path != NULL) && ((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) || @@ -1992,23 +1939,28 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea free(path); } } + // try pm3 dirs in current repo workdir (dev mode) + PrintAndLogEx(DEBUG, "Searching PM3 dirs in current workdir"); if ((exec_path != NULL) && ((strcmp(TRACES_SUBDIR, pm3dir) == 0) || (strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) || (strcmp(BOOTROM_SUBDIR, pm3dir) == 0) || (strcmp(FULLIMAGE_SUBDIR, pm3dir) == 0))) { - const char *above = "../"; - char *path = calloc(strlen(exec_path) + strlen(above) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); - if (path == NULL) + char *path = calloc(strlen(exec_path) + strlen(ABOVE) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); + if (path == NULL) { goto out; + } + strcpy(path, exec_path); - strcat(path, above); + strcat(path, ABOVE); strcat(path, pm3dir); strcat(path, filename); + if ((g_debugMode == 2) && (!silent)) { PrintAndLogEx(INFO, "Searching %s", path); } + if (fileExists(path)) { free(filename); *foundpath = path; @@ -2020,18 +1972,24 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea free(path); } } + // try pm3 dirs in pm3 installation dir (install mode) + PrintAndLogEx(DEBUG, "Searching PM3 installation dir paths"); if (exec_path != NULL) { char *path = calloc(strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); - if (path == NULL) + if (path == NULL) { goto out; + } + strcpy(path, exec_path); strcat(path, PM3_SHARE_RELPATH); strcat(path, pm3dir); strcat(path, filename); + if ((g_debugMode == 2) && (!silent)) { PrintAndLogEx(INFO, "Searching %s", path); } + if (fileExists(path)) { free(filename); *foundpath = path; @@ -2067,15 +2025,15 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con free(filename); return PM3_EFILE; } + int res = searchFinalFile(foundpath, pm3dir, filename, silent); if (res != PM3_SUCCESS) { - if ((res == PM3_EFILE) && (!silent)) + if ((res == PM3_EFILE) && (!silent)) { PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename); + } + } free(filename); return res; - } - free(filename); - return PM3_SUCCESS; } int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) { @@ -2107,6 +2065,10 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed"); return PM3_EINVARG; } + case MCT: { + res = loadFileMCT_safe(fn, pdump, dumplen); + break; + } } if (res != PM3_SUCCESS) { diff --git a/client/src/fileutils.h b/client/src/fileutils.h index 18e0fbd7e..81cb13e05 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -56,15 +56,16 @@ typedef enum { EML, JSON, DICTIONARY, + MCT, } DumpFileType_t; int fileExists(const char *filename); -//bool create_path(const char *dirname); // set a path in the path list g_session.defaultPaths bool setDefaultPath(savePaths_t pathIndex, const char *path); char *newfilenamemcopy(const char *preferredName, const char *suffix); +char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t save_path); /** * @brief Utility function to save data to a binary file. This method takes a preferred name, but if that @@ -104,7 +105,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t * @return 0 for ok, 1 for failz */ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *)); -int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)); +int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *), savePaths_t e_save_path); int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose); int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite); /** STUB @@ -141,20 +142,6 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen); */ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector); -/** - * @brief Utility function to load data from a binary file. This method takes a preferred name. - * E.g. dumpdata-15.bin - * - * @param preferredName - * @param suffix the file suffix. Including the ".". - * @param data The data array to store the loaded bytes from file - * @param maxdatalen the number of bytes that your data array has - * @param datalen the number of bytes loaded from file - * @return PM3_SUCCESS for ok, PM3_E* for failz -*/ -int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen); - - /** * @brief Utility function to load data from a binary file. This method takes a preferred name. * E.g. dumpdata-15.bin, tries to search for it, and allocated memory. @@ -176,9 +163,19 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, * @param datalen the number of bytes loaded from file * @return 0 for ok, 1 for failz */ -int loadFileEML(const char *preferredName, void *data, size_t *datalen); int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen); +/** + * @brief Utility function to load data from a textfile (MCT). This method takes a preferred name. + * E.g. dumpdata-15.mct + * + * @param preferredName + * @param data The data array to store the loaded bytes from file + * @param datalen the number of bytes loaded from file + * @return 0 for ok, 1 for failz +*/ +int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen); + /** * @brief Utility function to load data from a JSON textfile. This method takes a preferred name. * E.g. dumpdata-15.json diff --git a/client/src/flash.c b/client/src/flash.c index 20729b2da..cca2de7b1 100644 --- a/client/src/flash.c +++ b/client/src/flash.c @@ -236,11 +236,14 @@ static int check_segs(flash_file_t *ctx, int can_write_bl, uint32_t flash_size) } static int print_and_validate_version(struct version_information_t *vi) { - if (vi->magic != VERSION_INFORMATION_MAGIC) + if (vi->magic != VERSION_INFORMATION_MAGIC) { return PM3_EFILE; + } + char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image FormatVersionInformation(temp, sizeof(temp), "", vi); PrintAndLogEx(SUCCESS, _CYAN_("ELF file version") _YELLOW_(" %s"), temp); + if (strlen(g_version_information.armsrc) == 9) { if (strncmp(vi->armsrc, g_version_information.armsrc, 9) != 0) { PrintAndLogEx(WARNING, _RED_("ARM firmware does not match the source at the time the client was compiled")); diff --git a/client/src/preferences.c b/client/src/preferences.c index 99fb20d30..e3aef4ccb 100644 --- a/client/src/preferences.c +++ b/client/src/preferences.c @@ -122,17 +122,18 @@ int preferences_save(void) { PrintAndLogEx(INFO, "Saving preferences..."); char *fn = prefGetFilename(); - int fnLen = strlen(fn) + 5; // .bak\0 + int fn_len = strlen(fn) + 5; // .bak\0 // [FILENAME_MAX+sizeof(preferencesFilename)+10] - char *backupFilename = (char *)calloc(fnLen, sizeof(uint8_t)); + char *backupFilename = (char *)calloc(fn_len, sizeof(uint8_t)); if (backupFilename == NULL) { PrintAndLogEx(ERR, "failed to allocate memory"); free(fn); return PM3_EMALLOC; } - snprintf(backupFilename, fnLen, "%s.bak", fn); + snprintf(backupFilename, fn_len, "%s.bak", fn); + // remove old backup file if (fileExists(backupFilename)) { if (remove(backupFilename) != 0) { PrintAndLogEx(FAILED, "Error - could not delete old settings backup file \"%s\"", backupFilename); @@ -142,6 +143,7 @@ int preferences_save(void) { } } + // rename file to backup file if (fileExists(fn)) { if (rename(fn, backupFilename) != 0) { PrintAndLogEx(FAILED, "Error - could not backup settings file \"%s\" to \"%s\"", fn, backupFilename); @@ -154,8 +156,9 @@ int preferences_save(void) { uint8_t dummyData = 0x00; size_t dummyDL = 0x01; - if (saveFileJSON(fn, jsfCustom, &dummyData, dummyDL, &preferences_save_callback) != PM3_SUCCESS) + if (saveFileJSONex(fn, jsfCustom, &dummyData, dummyDL, true, &preferences_save_callback, spItemCount) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Error saving preferences to \"%s\"", fn); + } free(fn); free(backupFilename); diff --git a/doc/md/Installation_Instructions/Mac-OS-X-MacPorts-Installation-Instructions.md b/doc/md/Installation_Instructions/Mac-OS-X-MacPorts-Installation-Instructions.md index 6fa5a1754..3ea25c20d 100644 --- a/doc/md/Installation_Instructions/Mac-OS-X-MacPorts-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Mac-OS-X-MacPorts-Installation-Instructions.md @@ -2,7 +2,6 @@ # Mac OS X - MacPorts automatic installation -

These insturctions won't work on Apple Silicon yet!

An arm64 native build of arm-none-eabi-gcc is still not available (as of 2021-11-26).
# Table of Contents - [Mac OS X - MacPorts automatic installation](#mac-os-x---macports-automatic-installation) @@ -23,70 +22,82 @@ 1. Have MacPorts installed. Visit https://www.macports.org/ for more information. - * MacPorts may require a bit more setup. You first need to set up your PATH variable: - - ```bash - export "/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/local/sbin:$PATH" - ``` - - For a somewhat seamless development environment: - - ```bash - export C_INCLUDE_PATH="/opt/local/include" - export CPLUS_INCLUDE_PATH="/opt/local/include" - export LIBRARY_PATH="/opt/local/lib" - export LDFLAGS="-L/opt/local/lib" - export CFLAGS="-I/opt/local/include" - export CPPFLAGS="-isystem/opt/local/include -I/opt/local/include" - ``` - -## Installing latest releases +## Installing stable releases directly ^[Top](#top) -Packaging for latest releases are available on MacPorts with the port name `proxmark3-iceman`, with a variant for PM3GENERIC firmwares available as `+pm3generic`. +Packaging for latest releases are available on MacPorts with the port name [`proxmark3-iceman`](https://ports.macports.org/port/proxmark3-iceman/details/), with a variant for PM3GENERIC firmwares available as `+pm3generic`. Installing is as simple as `sudo port install proxmark3-iceman` and if you want to install for PM3GENERIC, you can run `sudo port install proxmark3-iceman +pm3generic` instead. + ## Build from source ^[Top](#top) These instructions will show how to setup the environment on OSX to the point where you'll be able to clone and compile the repo by yourself, as on Linux, Windows, etc. -1. Have MacPorts installed. See above for details. +1. Have MacPorts installed. Visit https://www.macports.org/ for more information. + + * Since you're going to compile directly; this will require a bit more setup, you first need to set up your PATH variable (we assume your MacPorts prefix is located at its default, which is `/opt/local`) in your shell rc file: + + ```bash + export MACPORTS_PREFIX="/opt/local" + # we assume you'll use GNU coreutils; which is also a required dependency for proxmark3 + # install it with `sudo port install coreutils` + export "$MACPORTS_PREFIX/libexec/gnubin:$MACPORTS_PREFIX/bin:$MACPORTS_PREFIX/sbin:$PATH" + ``` + + For a somewhat seamless development environment, you can use these in your shell rc file: + + ```bash + export C_INCLUDE_PATH="$MACPORTS_PREFIX/include:$C_INCLUDE_PATH" + export CPLUS_INCLUDE_PATH="$MACPORTS_PREFIX/include:$CPLUS_INCLUDE_PATH" + export LIBRARY_PATH="$MACPORTS_PREFIX/lib:$LIBRARY_PATH" + export LDFLAGS="-L$MACPORTS_PREFIX/lib $LDFLAGS" + export CFLAGS="-I$MACPORTS_PREFIX/include $CFLAGS" + export CPPFLAGS="-isystem$MACPORTS_PREFIX/include -I$MACPORTS_PREFIX/include $CPPFLAGS" + export PKG_CONFIG_PATH="$MACPORTS_PREFIX/lib/pkgconfig:$MACPORTS_PREFIX/share/pkgconfig:$PKG_CONFIG_PATH" + ``` 2. Install dependencies: - ``` - sudo port install readline qt5 qt5-qtbase pkgconfig arm-none-eabi-gcc arm-none-eabi-binutils lua52 coreutils openssl@3 + ```bash + sudo port install readline jansson lua52 python311 bzip2 openssl11 arm-none-eabi-gcc arm-none-eabi-binutils coreutils qt5 qt5-qtbase pkgconfig ``` 3. Clamp Python version for pkg-config MacPorts doesn't handle Python version defaults when it comes to pkg-config. So even if you have done: - ``` - sudo port install python39 cython39 + ```bash + sudo port install python311 cython311 - sudo port select --set python python39 # this also makes calls to "python" operate on python3.9 - sudo port select --set python3 python39 - sudo port select --set cython cython39 + sudo port select --set python python311 # this also makes calls to "python" operate on python3.11 + sudo port select --set python3 python311 + sudo port select --set cython cython311 ``` This won't set a default python3.pc (and python3-embed.pc) under the MacPorts pkgconfig includes folder. To fix that, follow these steps: - ``` + ```bash cd /opt/local/lib/pkgconfig - sudo ln -svf python3.pc python-3.9.pc - sudo ln -svf python3-embed.pc python-3.9-embed.pc + sudo ln -svf python3.pc python-3.11.pc + sudo ln -svf python3-embed.pc python-3.11-embed.pc + ``` + + _Or_ you can use a framework definition in your shell rc file: + + ```bash + export MACPORTS_FRAMEWORKS_DIR="$MACPORTS_PREFIX/Library/Frameworks" + export PYTHON_FRAMEWORK_DIR="$MACPORTS_FRAMEWORKS_DIR:/Python.framework/Versions/3.11" + export PKG_CONFIG_PATH="$PYTHON_FRAMEWORK_DIR:$PKG_CONFIG_PATH" ``` 4. (optional) Install makefile dependencies: - ``` - sudo port install recode - sudo port install astyle + ```bash + sudo port install recode astyle ``` @@ -103,7 +114,7 @@ cd proxmark3 Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). From there, you can follow the original instructions. -_Take extra note to instructions if you don't have a Proxmark3 RDV4 device._ +_Take extra note to instructions if you **don't** have a Proxmark3 RDV4 device._ To flash on OS X, better to enter the bootloader mode manually, else you may experience errors. @@ -125,4 +136,3 @@ If you want to manually select serial port, remember that the Proxmark3 port is ```sh proxmark3 /dev/ttyACM0 => proxmark3 /dev/tty.usbmodemiceman1 ``` -