Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
Davi Mikael 2023-04-24 22:58:14 -03:00 committed by GitHub
commit bac259e7c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 285 additions and 307 deletions

View file

@ -9,7 +9,7 @@ jobs:
- name: Changelog Reminder - name: Changelog Reminder
uses: peterjgrainger/action-changelog-reminder@v1.2.0 uses: peterjgrainger/action-changelog-reminder@v1.2.0
with: with:
changelog_regex: '/CHANGELOG.md' changelog_regex: 'CHANGELOG.md'
customPrMessage: 'You are welcome to add an entry to the CHANGELOG.md as well' customPrMessage: 'You are welcome to add an entry to the CHANGELOG.md as well'
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... 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] ## [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) - Changed `lf t55xx dump --ns` - now supports `no save` of memory (@iceman1001)
- Fixed the USB enumeration process (@wh201906) - Fixed the USB enumeration process (@wh201906)
- Fixed `hf mf rdsc` - now correctly gets size in bytes when sector is larger than 32 (@iceman1001) - 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) - Added `hf legic einfo` - views emulator menory (@0xdeb)
- Changed `hf legic view` - now also print the decoded info of the dump file (@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) - 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] ## [Nitride.4.16191][2023-01-29]
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)

View file

@ -85,6 +85,8 @@ DumpFileType_t getfiletype(const char *filename) {
o = JSON; o = JSON;
} else if (str_endswith(s, "dic")) { } else if (str_endswith(s, "dic")) {
o = DICTIONARY; o = DICTIONARY;
} else if (str_endswith(s, "mct")) {
o = MCT;
} else { } else {
// mfd, trc, trace is binary // mfd, trc, trace is binary
o = BIN; o = BIN;
@ -112,27 +114,6 @@ int fileExists(const char *filename) {
return result == 0; 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. * @brief checks if path is directory.
* @param filename * @param filename
@ -152,68 +133,6 @@ static bool is_directory(const char *filename) {
return S_ISDIR(st.st_mode) != 0; 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) { bool setDefaultPath(savePaths_t pathIndex, const char *path) {
if (pathIndex < spItemCount) { if (pathIndex < spItemCount) {
@ -262,37 +181,55 @@ static size_t path_size(savePaths_t a) {
} }
char *newfilenamemcopy(const char *preferredName, const char *suffix) { 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) { if (preferredName == NULL || suffix == NULL) {
return NULL; return NULL;
} }
uint16_t p_namelen = strlen(preferredName); uint16_t p_namelen = strlen(preferredName);
if (str_endswith(preferredName, suffix)) if (str_endswith(preferredName, suffix)) {
p_namelen -= strlen(suffix); p_namelen -= strlen(suffix);
}
// 10: room for filenum to ensure new filename int save_path_len = path_size(e_save_path);
const size_t len = p_namelen + strlen(suffix) + 1 + 10;
int foobar = path_size(spDefault); // 1: null terminator
(void) foobar; // 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)); char *fileName = (char *) calloc(len, sizeof(uint8_t));
if (fileName == NULL) { if (fileName == NULL) {
return 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; 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)) { 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++; num++;
} }
PrintAndLogEx(INFO, "FILE PATH: %s", fileName);
return fileName; return fileName;
} }
// --------- SAVE FILES
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) { int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
@ -321,13 +258,14 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// dump file
int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) { int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
char *fileName = newfilenamemcopy(preferredName, ".eml"); char *fileName = newfilenamemcopyEx(preferredName, ".eml", spDump);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -371,16 +309,19 @@ out:
return retval; 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 *)) { 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) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
}
char *fileName = newfilenamemcopy(preferredName, ".json"); char *fileName = newfilenamemcopyEx(preferredName, ".json", e_save_path);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -719,7 +660,7 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool
if (overwrite) if (overwrite)
filename = filenamemcopy(preferredName, ".json"); filename = filenamemcopy(preferredName, ".json");
else else
filename = newfilenamemcopy(preferredName, ".json"); filename = newfilenamemcopyEx(preferredName, ".json", spDump);
if (filename == NULL) if (filename == NULL)
return PM3_EMALLOC; return PM3_EMALLOC;
@ -739,13 +680,14 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool
return PM3_EFILE; return PM3_EFILE;
} }
// wave file of trace,
int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) { int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
char *fileName = newfilenamemcopy(preferredName, ".wav"); char *fileName = newfilenamemcopyEx(preferredName, ".wav", spTrace);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -791,13 +733,14 @@ out:
return retval; return retval;
} }
// Signal trace file, PM3
int saveFilePM3(const char *preferredName, int *data, size_t datalen) { int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
char *fileName = newfilenamemcopy(preferredName, ".pm3"); char *fileName = newfilenamemcopyEx(preferredName, ".pm3", spTrace);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -824,11 +767,12 @@ out:
return retval; return retval;
} }
// key file dump
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) { int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) {
if (e_sector == NULL) return PM3_EINVARG; if (e_sector == NULL) return PM3_EINVARG;
char *fileName = newfilenamemcopy(preferredName, ".bin"); char *fileName = newfilenamemcopyEx(preferredName, ".bin", spDump);
if (fileName == NULL) return PM3_EMALLOC; if (fileName == NULL) return PM3_EMALLOC;
FILE *f = fopen(fileName, "wb"); FILE *f = fopen(fileName, "wb");
@ -866,66 +810,7 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) { // --------- LOAD FILES
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;
}
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) { int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) {
return loadFile_safeEx(preferredName, suffix, pdata, datalen, true); 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; *datalen = bytes_read;
if (verbose) if (verbose) {
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName); PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
}
return PM3_SUCCESS; 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) { int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
char *path; char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false); 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; 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 *)) { 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); 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) { 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 // explicit absolute (/) or relative path (./) => try only to match it directly
char *filename = calloc(strlen(searchname) + 1, sizeof(char)); char *filename = calloc(strlen(searchname) + 1, sizeof(char));
if (filename == NULL) return PM3_EMALLOC; if (filename == NULL) {
return PM3_EMALLOC;
}
strcpy(filename, searchname); strcpy(filename, searchname);
if ((g_debugMode == 2) && (!silent)) { 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] == '/')) || if (((strlen(filename) > 1) && (filename[0] == '/')) ||
((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) { ((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) {
if (fileExists(filename)) { goto out;
*foundpath = filename; }
// 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)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Found %s", *foundpath); PrintAndLogEx(INFO, "Found %s", *foundpath);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} else { } 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) // try pm3 dirs in user .proxmark3 (user mode)
PrintAndLogEx(DEBUG, "Searching user .proxmark3 paths");
const char *user_path = get_my_user_directory(); const char *user_path = get_my_user_directory();
if (user_path != NULL) { if (user_path != NULL) {
char *path = calloc(strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); 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; goto out;
}
strcpy(path, user_path); strcpy(path, user_path);
strcat(path, PM3_USER_DIRECTORY); strcat(path, PM3_USER_DIRECTORY);
strcat(path, pm3dir); strcat(path, pm3dir);
strcat(path, filename); strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path); PrintAndLogEx(INFO, "Searching %s", path);
} }
if (fileExists(path)) { if (fileExists(path)) {
free(filename); free(filename);
*foundpath = path; *foundpath = path;
@ -1959,7 +1904,9 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path); free(path);
} }
} }
// try pm3 dirs in current client workdir (dev mode) // try pm3 dirs in current client workdir (dev mode)
PrintAndLogEx(DEBUG, "Searching current workdir paths");
const char *exec_path = get_my_executable_directory(); const char *exec_path = get_my_executable_directory();
if ((exec_path != NULL) && if ((exec_path != NULL) &&
((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) || ((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) ||
@ -1992,23 +1939,28 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path); free(path);
} }
} }
// try pm3 dirs in current repo workdir (dev mode) // try pm3 dirs in current repo workdir (dev mode)
PrintAndLogEx(DEBUG, "Searching PM3 dirs in current workdir");
if ((exec_path != NULL) && if ((exec_path != NULL) &&
((strcmp(TRACES_SUBDIR, pm3dir) == 0) || ((strcmp(TRACES_SUBDIR, pm3dir) == 0) ||
(strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) || (strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) ||
(strcmp(BOOTROM_SUBDIR, pm3dir) == 0) || (strcmp(BOOTROM_SUBDIR, pm3dir) == 0) ||
(strcmp(FULLIMAGE_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));
char *path = calloc(strlen(exec_path) + strlen(above) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); if (path == NULL) {
if (path == NULL)
goto out; goto out;
}
strcpy(path, exec_path); strcpy(path, exec_path);
strcat(path, above); strcat(path, ABOVE);
strcat(path, pm3dir); strcat(path, pm3dir);
strcat(path, filename); strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path); PrintAndLogEx(INFO, "Searching %s", path);
} }
if (fileExists(path)) { if (fileExists(path)) {
free(filename); free(filename);
*foundpath = path; *foundpath = path;
@ -2020,18 +1972,24 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path); free(path);
} }
} }
// try pm3 dirs in pm3 installation dir (install mode) // try pm3 dirs in pm3 installation dir (install mode)
PrintAndLogEx(DEBUG, "Searching PM3 installation dir paths");
if (exec_path != NULL) { if (exec_path != NULL) {
char *path = calloc(strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); 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; goto out;
}
strcpy(path, exec_path); strcpy(path, exec_path);
strcat(path, PM3_SHARE_RELPATH); strcat(path, PM3_SHARE_RELPATH);
strcat(path, pm3dir); strcat(path, pm3dir);
strcat(path, filename); strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path); PrintAndLogEx(INFO, "Searching %s", path);
} }
if (fileExists(path)) { if (fileExists(path)) {
free(filename); free(filename);
*foundpath = path; *foundpath = path;
@ -2067,15 +2025,15 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con
free(filename); free(filename);
return PM3_EFILE; return PM3_EFILE;
} }
int res = searchFinalFile(foundpath, pm3dir, filename, silent); int res = searchFinalFile(foundpath, pm3dir, filename, silent);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
if ((res == PM3_EFILE) && (!silent)) if ((res == PM3_EFILE) && (!silent)) {
PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename); PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
}
}
free(filename); free(filename);
return res; return res;
}
free(filename);
return PM3_SUCCESS;
} }
int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) { 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"); PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed");
return PM3_EINVARG; return PM3_EINVARG;
} }
case MCT: {
res = loadFileMCT_safe(fn, pdump, dumplen);
break;
}
} }
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {

View file

@ -56,15 +56,16 @@ typedef enum {
EML, EML,
JSON, JSON,
DICTIONARY, DICTIONARY,
MCT,
} DumpFileType_t; } DumpFileType_t;
int fileExists(const char *filename); int fileExists(const char *filename);
//bool create_path(const char *dirname);
// set a path in the path list g_session.defaultPaths // set a path in the path list g_session.defaultPaths
bool setDefaultPath(savePaths_t pathIndex, const char *path); bool setDefaultPath(savePaths_t pathIndex, const char *path);
char *newfilenamemcopy(const char *preferredName, const char *suffix); 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 * @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 * @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 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 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); int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite);
/** STUB /** 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); 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. * @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. * 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 * @param datalen the number of bytes loaded from file
* @return 0 for ok, 1 for failz * @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); 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. * @brief Utility function to load data from a JSON textfile. This method takes a preferred name.
* E.g. dumpdata-15.json * E.g. dumpdata-15.json

View file

@ -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) { 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; return PM3_EFILE;
}
char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image
FormatVersionInformation(temp, sizeof(temp), "", vi); FormatVersionInformation(temp, sizeof(temp), "", vi);
PrintAndLogEx(SUCCESS, _CYAN_("ELF file version") _YELLOW_(" %s"), temp); PrintAndLogEx(SUCCESS, _CYAN_("ELF file version") _YELLOW_(" %s"), temp);
if (strlen(g_version_information.armsrc) == 9) { if (strlen(g_version_information.armsrc) == 9) {
if (strncmp(vi->armsrc, g_version_information.armsrc, 9) != 0) { 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")); PrintAndLogEx(WARNING, _RED_("ARM firmware does not match the source at the time the client was compiled"));

View file

@ -122,17 +122,18 @@ int preferences_save(void) {
PrintAndLogEx(INFO, "Saving preferences..."); PrintAndLogEx(INFO, "Saving preferences...");
char *fn = prefGetFilename(); char *fn = prefGetFilename();
int fnLen = strlen(fn) + 5; // .bak\0 int fn_len = strlen(fn) + 5; // .bak\0
// [FILENAME_MAX+sizeof(preferencesFilename)+10] // [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) { if (backupFilename == NULL) {
PrintAndLogEx(ERR, "failed to allocate memory"); PrintAndLogEx(ERR, "failed to allocate memory");
free(fn); free(fn);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
snprintf(backupFilename, fnLen, "%s.bak", fn); snprintf(backupFilename, fn_len, "%s.bak", fn);
// remove old backup file
if (fileExists(backupFilename)) { if (fileExists(backupFilename)) {
if (remove(backupFilename) != 0) { if (remove(backupFilename) != 0) {
PrintAndLogEx(FAILED, "Error - could not delete old settings backup file \"%s\"", backupFilename); 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 (fileExists(fn)) {
if (rename(fn, backupFilename) != 0) { if (rename(fn, backupFilename) != 0) {
PrintAndLogEx(FAILED, "Error - could not backup settings file \"%s\" to \"%s\"", fn, backupFilename); 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; uint8_t dummyData = 0x00;
size_t dummyDL = 0x01; 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); PrintAndLogEx(ERR, "Error saving preferences to \"%s\"", fn);
}
free(fn); free(fn);
free(backupFilename); free(backupFilename);

View file

@ -2,7 +2,6 @@
<a id="Top"></a> <a id="Top"></a>
# Mac OS X - MacPorts automatic installation # Mac OS X - MacPorts automatic installation
<b><h3>These insturctions won't work on Apple Silicon yet!</h3> An arm64 native build of arm-none-eabi-gcc is still not available (as of 2021-11-26).</b>
# Table of Contents # Table of Contents
- [Mac OS X - MacPorts automatic installation](#mac-os-x---macports-automatic-installation) - [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. 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: ## Installing stable releases directly
```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
^[Top](#top) ^[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. 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 ## Build from source
^[Top](#top) ^[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. 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: 2. Install dependencies:
``` ```bash
sudo port install readline qt5 qt5-qtbase pkgconfig arm-none-eabi-gcc arm-none-eabi-binutils lua52 coreutils openssl@3 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 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: MacPorts doesn't handle Python version defaults when it comes to pkg-config. So even if you have done:
``` ```bash
sudo port install python39 cython39 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 python python311 # this also makes calls to "python" operate on python3.11
sudo port select --set python3 python39 sudo port select --set python3 python311
sudo port select --set cython cython39 sudo port select --set cython cython311
``` ```
This won't set a default python3.pc (and python3-embed.pc) under the MacPorts pkgconfig includes folder. This won't set a default python3.pc (and python3-embed.pc) under the MacPorts pkgconfig includes folder.
To fix that, follow these steps: To fix that, follow these steps:
``` ```bash
cd /opt/local/lib/pkgconfig cd /opt/local/lib/pkgconfig
sudo ln -svf python3.pc python-3.9.pc sudo ln -svf python3.pc python-3.11.pc
sudo ln -svf python3-embed.pc python-3.9-embed.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: 4. (optional) Install makefile dependencies:
``` ```bash
sudo port install recode sudo port install recode astyle
sudo port install 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). 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. 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. 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 ```sh
proxmark3 /dev/ttyACM0 => proxmark3 /dev/tty.usbmodemiceman1 proxmark3 /dev/ttyACM0 => proxmark3 /dev/tty.usbmodemiceman1
``` ```