diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 6a7a7e411..f185d4456 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -723,6 +723,7 @@ void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyL static int CmdHFMFPChk(const char *cmd) { int res; + FILE *dictionary_file = NULL; uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; size_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; @@ -775,23 +776,20 @@ static int CmdHFMFPChk(const char *cmd) { return PM3_EINVARG; } -/* char *dict_path; - int res = searchFile(&dict_path, DICTIONARIES_SUBDIR, filename, ".dic", false); + char *dict_path; + res = searchFile(&dict_path, DICTIONARIES_SUBDIR, (char *)dict_filename, ".dic", false); if (res != PM3_SUCCESS) { CLIParserFree(); return PM3_EFILE; } - f = fopen(dict_path, "r"); - if (!f) { + dictionary_file = fopen(dict_path, "r"); + if (!dictionary_file) { PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path); free(dict_path); CLIParserFree(); return PM3_EFILE; } - free(dict_path); - - - */ + free(dict_path); bool pattern1b = arg_get_lit(7); bool pattern2b = arg_get_lit(8); @@ -801,6 +799,12 @@ static int CmdHFMFPChk(const char *cmd) { CLIParserFree(); return PM3_EINVARG; } + + if (dictionary_file && (pattern1b || pattern2b)) { + PrintAndLogEx(ERROR, "Pattern search mode and dictionary mode can't be used in one command."); + CLIParserFree(); + return PM3_EINVARG; + } uint32_t startPattern = 0x0000; uint8_t vpattern[2]; @@ -839,6 +843,7 @@ static int CmdHFMFPChk(const char *cmd) { if (endSector < startSector) endSector = startSector; + // 1-byte pattern search mode if (pattern1b) { for (int i = 0; i < 0x100; i++) memset(keyList[i], i, 16); @@ -846,8 +851,16 @@ static int CmdHFMFPChk(const char *cmd) { keyListLen = 0x100; } + // 2-byte pattern search mode if (pattern2b) Fill2bPattern(keyList, &keyListLen, &startPattern); + + // dictionary mode + if (dictionary_file) { + size_t endFilePosition = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), &keyListLen, 16, NULL, 0, &endFilePosition); + printf("---endFilePosition %d", endFilePosition); + } if (keyListLen == 0) { for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { diff --git a/client/fileutils.c b/client/fileutils.c index 83f3635a4..a69de8d96 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -745,12 +745,6 @@ out: } int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt) { - - if (data == NULL) return PM3_EINVARG; - char *path; - if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS) - return PM3_EFILE; - // t5577 == 4bytes // mifare == 6 bytes // mf plus == 16 bytes @@ -759,6 +753,20 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { keylen = 6; } + + return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL); +} + +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition) { + if (endFilePosition) + *endFilePosition = 0; + if (data == NULL) return PM3_EINVARG; + uint16_t vkeycnt = 0; + + char *path; + if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS) + return PM3_EFILE; // double up since its chars keylen <<= 1; @@ -774,7 +782,10 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u retval = PM3_EFILE; goto out; } - + + if (startFilePosition) + fseek(f, startFilePosition, SEEK_SET); + // read file while (fgets(line, sizeof(line), f)) { @@ -789,30 +800,32 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u if (line[0] == '#') continue; - bool searchFail = false; - for (int i = 0; i < keylen; i++) { - if (!isxdigit(line[i])) { - PrintAndLogEx(FAILED, "file content error (pos %d). '%s' must include " _BLUE_("%2d") "HEX symbols", i + 1, line, keylen); - searchFail = true; - break; - } - } - if (searchFail) + if (CheckStringIsHEXValue(line)) continue; + // cant store more data + if (maxdatalen && (counter + keylen > maxdatalen)) { + retval = 1; + int pos = ftell(f) - strlen(line) - 2; // 2 - `\r\n` + if (endFilePosition && (pos > 0)) + *endFilePosition = pos; + break; + } - uint64_t key = strtoull(line, NULL, 16); - - num_to_bytes(key, keylen >> 1, data + counter); - (*keycnt)++; + if (hex_to_bytes(line, data + counter, keylen >> 1) != (keylen >> 1)) + continue; + + vkeycnt++; memset(line, 0, sizeof(line)); counter += (keylen >> 1); } fclose(f); - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), *keycnt, path); + PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); if (datalen) *datalen = counter; + if (keycnt) + *keycnt = vkeycnt; out: free(path); return retval; @@ -887,15 +900,7 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key if (line[0] == '#') continue; - bool searchFail = false; - for (int i = 0; i < keylen; i++) { - if (!isxdigit(line[i])) { - PrintAndLogEx(FAILED, "file content error (pos %d). '%s' must include " _BLUE_("%2d") "HEX symbols", i + 1, line, keylen); - searchFail = true; - break; - } - } - if (searchFail) + if (CheckStringIsHEXValue(line)) continue; uint64_t key = strtoull(line, NULL, 16); diff --git a/client/fileutils.h b/client/fileutils.h index bfd418a2c..58d05d366 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -176,13 +176,29 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ * * @param preferredName * @param data The data array to store the loaded bytes from file - * @param maxdatalen maximum size of data array in bytes * @param datalen the number of bytes loaded from file * @param keylen the number of bytes a key per row is * @return 0 for ok, 1 for failz */ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt); +/** + * @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name. + * E.g. mfc_default_keys.dic + * can be executed several times for big dictionaries and checks length of buffer + * + * @param preferredName + * @param data The data array to store the loaded bytes from file + * @param maxdatalen maximum size of data array in bytes + * @param datalen the number of bytes loaded from file + * @param keylen the number of bytes a key per row is + * @param startFilePosition + * @param endFilePosition + * @return 0 for ok, 1 for failz +*/ +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition); + /** * @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name. * E.g. mfc_default_keys.dic