mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-07-06 04:51:36 -07:00
text & style
This commit is contained in:
parent
911d4f9df2
commit
2d610b8dc0
11 changed files with 124 additions and 99 deletions
|
@ -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]
|
||||||
|
- Added the `PM3ULTIMATE` platform in the build / docs. *untested* (@iceman1001)
|
||||||
|
- Added fpga compilation for PM3ULTIMATE device (@n-hutton)
|
||||||
- Updated the ATR list (@iceman1001)
|
- Updated the ATR list (@iceman1001)
|
||||||
- Fixed fpga binary images to use fixed seed 2 (@n-hutton)
|
- Fixed fpga binary images to use fixed seed 2 (@n-hutton)
|
||||||
- Changed `hf iclass sim -t 7` - implemented simulation that glitches key block responses (@antiklesys)
|
- Changed `hf iclass sim -t 7` - implemented simulation that glitches key block responses (@antiklesys)
|
||||||
|
|
|
@ -14,6 +14,9 @@ PLATFORM=PM3RDV4
|
||||||
#PLATFORM=PM3ICOPYX
|
#PLATFORM=PM3ICOPYX
|
||||||
#PLATFORM_EXTRAS=FLASH
|
#PLATFORM_EXTRAS=FLASH
|
||||||
|
|
||||||
|
# For PM3 Ultimate:
|
||||||
|
# uncomment the line below
|
||||||
|
#PLATFORM=PM3ULTIMATE
|
||||||
|
|
||||||
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
|
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
|
||||||
#PLATFORM_EXTRAS=BTADDON
|
#PLATFORM_EXTRAS=BTADDON
|
||||||
|
|
|
@ -2250,7 +2250,8 @@ write_dump:
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode, bool shallow_mod) {
|
static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata, uint8_t *KEY, bool use_credit_key,
|
||||||
|
bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode, bool shallow_mod) {
|
||||||
|
|
||||||
iclass_writeblock_req_t payload = {
|
iclass_writeblock_req_t payload = {
|
||||||
.req.use_raw = rawkey,
|
.req.use_raw = rawkey,
|
||||||
|
@ -5067,56 +5068,49 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
bool use_vb6kdf = arg_get_lit(ctx, 7);
|
|
||||||
int fnlen = 0;
|
int fnlen = 0;
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
|
||||||
bool use_elite = arg_get_lit(ctx, 5);
|
|
||||||
bool use_raw = arg_get_lit(ctx, 6);
|
|
||||||
if (use_vb6kdf) {
|
|
||||||
use_elite = true;
|
|
||||||
} else {
|
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
int csn_len = 0;
|
int csn_len = 0;
|
||||||
uint8_t csn[8] = {0};
|
uint8_t csn[8] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 2, csn, &csn_len);
|
CLIGetHexWithReturn(ctx, 2, csn, &csn_len);
|
||||||
|
|
||||||
if (csn_len > 0) {
|
|
||||||
if (csn_len != 8) {
|
|
||||||
PrintAndLogEx(ERR, "CSN is incorrect length");
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int epurse_len = 0;
|
int epurse_len = 0;
|
||||||
uint8_t epurse[8] = {0};
|
uint8_t epurse[8] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 3, epurse, &epurse_len);
|
CLIGetHexWithReturn(ctx, 3, epurse, &epurse_len);
|
||||||
|
|
||||||
if (epurse_len > 0) {
|
|
||||||
if (epurse_len != 8) {
|
|
||||||
PrintAndLogEx(ERR, "ePurse is incorrect length");
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int macs_len = 0;
|
int macs_len = 0;
|
||||||
uint8_t macs[8] = {0};
|
uint8_t macs[8] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 4, macs, &macs_len);
|
CLIGetHexWithReturn(ctx, 4, macs, &macs_len);
|
||||||
|
|
||||||
if (macs_len > 0) {
|
bool use_elite = arg_get_lit(ctx, 5);
|
||||||
if (macs_len != 8) {
|
bool use_raw = arg_get_lit(ctx, 6);
|
||||||
PrintAndLogEx(ERR, "MAC is incorrect length");
|
bool use_vb6kdf = arg_get_lit(ctx, 7);
|
||||||
CLIParserFree(ctx);
|
|
||||||
return PM3_EINVARG;
|
if (use_vb6kdf == false) {
|
||||||
}
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// santity checks
|
||||||
|
|
||||||
|
if (csn_len > 0 && csn_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "CSN is incorrect length");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (epurse_len > 0 && epurse_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "ePurse is incorrect length");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macs_len > 0 && macs_len != 8) {
|
||||||
|
PrintAndLogEx(ERR, "MAC is incorrect length");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t CCNR[12];
|
uint8_t CCNR[12];
|
||||||
uint8_t MAC_TAG[4] = { 0, 0, 0, 0 };
|
uint8_t MAC_TAG[4] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
@ -5161,7 +5155,8 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
|
|
||||||
// Iclass_prekey_t
|
// Iclass_prekey_t
|
||||||
iclass_prekey_t *prekey = calloc(keycount, sizeof(iclass_prekey_t));
|
iclass_prekey_t *prekey = calloc(keycount, sizeof(iclass_prekey_t));
|
||||||
if (!prekey) {
|
if (prekey == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||||
free(keyBlock);
|
free(keyBlock);
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
@ -5182,13 +5177,14 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
// Sort mac list
|
// Sort mac list
|
||||||
qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT");
|
PrintAndLogEx(SUCCESS, "Searching for %s key...", _YELLOW_("DEBIT"));
|
||||||
iclass_prekey_t *item;
|
iclass_prekey_t *item;
|
||||||
iclass_prekey_t lookup;
|
iclass_prekey_t lookup;
|
||||||
memcpy(lookup.mac, MAC_TAG, 4);
|
memcpy(lookup.mac, MAC_TAG, 4);
|
||||||
|
|
||||||
// Binsearch
|
// Binsearch
|
||||||
item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
||||||
|
|
||||||
if (item != NULL) {
|
if (item != NULL) {
|
||||||
PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s"), sprint_hex(item->key, 8));
|
PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s"), sprint_hex(item->key, 8));
|
||||||
add_key(item->key);
|
add_key(item->key);
|
||||||
|
|
|
@ -48,21 +48,15 @@
|
||||||
#include "mifare/mifarehost.h"
|
#include "mifare/mifarehost.h"
|
||||||
#include "crypto/originality.h"
|
#include "crypto/originality.h"
|
||||||
|
|
||||||
|
|
||||||
// Defines for Saflok parsing
|
// Defines for Saflok parsing
|
||||||
#define SAFLOK_YEAR_OFFSET 1980
|
#define SAFLOK_YEAR_OFFSET 1980
|
||||||
#define SAFLOK_BASIC_ACCESS_BYTE_NUM 17
|
#define SAFLOK_BASIC_ACCESS_BYTE_NUM 17
|
||||||
#define SAFLOK_KEY_LENGTH 6
|
|
||||||
#define SAFLOK_UID_LENGTH 4 // Matches Mifare 4-byte UID
|
|
||||||
#define SAFLOK_MAGIC_TABLE_SIZE 192
|
|
||||||
#define SAFLOK_CHECK_SECTOR 1
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t a;
|
uint64_t a;
|
||||||
uint64_t b;
|
uint64_t b;
|
||||||
} MfClassicKeyPair;
|
} MfClassicKeyPair;
|
||||||
|
|
||||||
|
|
||||||
// Structure for Saflok key levels
|
// Structure for Saflok key levels
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t level_num;
|
uint8_t level_num;
|
||||||
|
@ -114,8 +108,8 @@ static const uint8_t saflok_c_aDecode[256] = {
|
||||||
// Function to decrypt Saflok card data
|
// Function to decrypt Saflok card data
|
||||||
static void DecryptSaflokCardData(
|
static void DecryptSaflokCardData(
|
||||||
const uint8_t strCard[SAFLOK_BASIC_ACCESS_BYTE_NUM],
|
const uint8_t strCard[SAFLOK_BASIC_ACCESS_BYTE_NUM],
|
||||||
// int length, // length is always SAFLOK_BASIC_ACCESS_BYTE_NUM
|
uint8_t decryptedCard[SAFLOK_BASIC_ACCESS_BYTE_NUM]
|
||||||
uint8_t decryptedCard[SAFLOK_BASIC_ACCESS_BYTE_NUM]) {
|
) {
|
||||||
int i;
|
int i;
|
||||||
int num;
|
int num;
|
||||||
int num2;
|
int num2;
|
||||||
|
@ -163,8 +157,8 @@ static uint8_t CalculateCheckSum(uint8_t data[SAFLOK_BASIC_ACCESS_BYTE_NUM]) {
|
||||||
static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t *sector1_info) {
|
static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t *sector1_info) {
|
||||||
(void)sector1_info; // Not directly used for payload parsing currently
|
(void)sector1_info; // Not directly used for payload parsing currently
|
||||||
|
|
||||||
if (!sector0_info) {
|
if (sector0_info == NULL) {
|
||||||
PrintAndLogEx(WARNING, "Saflok: Sector 0 information not available for parsing.");
|
PrintAndLogEx(WARNING, "Saflok: Sector 0 information not available for parsing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,16 +171,16 @@ static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t
|
||||||
num_to_bytes(sector0_info->Key[MF_KEY_A], MIFARE_KEY_SIZE, key_bytes_for_s0);
|
num_to_bytes(sector0_info->Key[MF_KEY_A], MIFARE_KEY_SIZE, key_bytes_for_s0);
|
||||||
key_type_for_s0 = MF_KEY_A; // MF_KEY_A is typically #define'd as 0x60
|
key_type_for_s0 = MF_KEY_A; // MF_KEY_A is typically #define'd as 0x60
|
||||||
s0_key_found = true;
|
s0_key_found = true;
|
||||||
PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key A for reading blocks.");
|
PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key A for reading blocks");
|
||||||
} else if (sector0_info->foundKey[MF_KEY_B]) { // Fallback to Key B for Sector 0
|
} else if (sector0_info->foundKey[MF_KEY_B]) { // Fallback to Key B for Sector 0
|
||||||
num_to_bytes(sector0_info->Key[MF_KEY_B], MIFARE_KEY_SIZE, key_bytes_for_s0);
|
num_to_bytes(sector0_info->Key[MF_KEY_B], MIFARE_KEY_SIZE, key_bytes_for_s0);
|
||||||
key_type_for_s0 = MF_KEY_B; // MF_KEY_B is typically #define'd as 0x61
|
key_type_for_s0 = MF_KEY_B; // MF_KEY_B is typically #define'd as 0x61
|
||||||
s0_key_found = true;
|
s0_key_found = true;
|
||||||
PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key B for reading blocks.");
|
PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key B for reading blocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s0_key_found) {
|
if (s0_key_found == false) {
|
||||||
PrintAndLogEx(WARNING, "Saflok: No known keys for Sector 0. Cannot read blocks 1 & 2 for parsing.");
|
PrintAndLogEx(WARNING, "Saflok: No known keys for Sector 0. Cannot read blocks 1 & 2 for parsing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,23 +189,23 @@ static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t
|
||||||
|
|
||||||
// Read absolute block 1 (data block within sector 0)
|
// Read absolute block 1 (data block within sector 0)
|
||||||
if (mf_read_block(1, key_type_for_s0, key_bytes_for_s0, block1_content) != PM3_SUCCESS) {
|
if (mf_read_block(1, key_type_for_s0, key_bytes_for_s0, block1_content) != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 1 using Sector 0 %s key.", (key_type_for_s0 == MF_KEY_A) ? "A" : "B");
|
PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 1 using Sector 0 %s key", (key_type_for_s0 == MF_KEY_A) ? "A" : "B");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 1.");
|
PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 1");
|
||||||
|
|
||||||
// Read absolute block 2 (data block within sector 0)
|
// Read absolute block 2 (data block within sector 0)
|
||||||
if (mf_read_block(2, key_type_for_s0, key_bytes_for_s0, block2_content) != PM3_SUCCESS) {
|
if (mf_read_block(2, key_type_for_s0, key_bytes_for_s0, block2_content) != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 2 using Sector 0 %s key.", (key_type_for_s0 == MF_KEY_A) ? "A" : "B");
|
PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 2 using Sector 0 %s key", (key_type_for_s0 == MF_KEY_A) ? "A" : "B");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 2.");
|
PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 2");
|
||||||
|
|
||||||
uint8_t basicAccess[SAFLOK_BASIC_ACCESS_BYTE_NUM];
|
uint8_t basicAccess[SAFLOK_BASIC_ACCESS_BYTE_NUM];
|
||||||
uint8_t decodedBA[SAFLOK_BASIC_ACCESS_BYTE_NUM];
|
uint8_t decodedBA[SAFLOK_BASIC_ACCESS_BYTE_NUM];
|
||||||
|
|
||||||
memcpy(basicAccess, block1_content, 16); // 16 bytes from Block 1
|
memcpy(basicAccess, block1_content, MFBLOCK_SIZE); // 16 bytes from Block 1
|
||||||
memcpy(basicAccess + 16, block2_content, 1); // 1 byte from Block 2
|
memcpy(basicAccess + MFBLOCK_SIZE, block2_content, 1); // 1 byte from Block 2
|
||||||
|
|
||||||
DecryptSaflokCardData(basicAccess, decodedBA);
|
DecryptSaflokCardData(basicAccess, decodedBA);
|
||||||
|
|
||||||
|
@ -298,18 +292,25 @@ static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t
|
||||||
// Handle day rollover for expiration
|
// Handle day rollover for expiration
|
||||||
static const uint8_t days_in_month_lookup[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 1-indexed month
|
static const uint8_t days_in_month_lookup[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 1-indexed month
|
||||||
if (expire_month > 0 && expire_month <= 12) {
|
if (expire_month > 0 && expire_month <= 12) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
uint8_t max_days = days_in_month_lookup[expire_month];
|
uint8_t max_days = days_in_month_lookup[expire_month];
|
||||||
if (expire_month == 2 && (expire_year % 4 == 0 && (expire_year % 100 != 0 || expire_year % 400 == 0))) {
|
if (expire_month == 2 &&
|
||||||
|
(expire_year % 4 == 0 &&
|
||||||
|
(expire_year % 100 != 0 || expire_year % 400 == 0))) {
|
||||||
max_days = 29; // Leap year
|
max_days = 29; // Leap year
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expire_day <= max_days) {
|
if (expire_day <= max_days) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_days == 0) { // Should not happen with valid month
|
if (max_days == 0) { // Should not happen with valid month
|
||||||
PrintAndLogEx(WARNING, "Saflok: Invalid day/month for expiration rollover calculation.");
|
PrintAndLogEx(WARNING, "Saflok: Invalid day/month for expiration rollover calculation");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
expire_day -= max_days;
|
expire_day -= max_days;
|
||||||
expire_month++;
|
expire_month++;
|
||||||
if (expire_month > 12) {
|
if (expire_month > 12) {
|
||||||
|
@ -317,8 +318,9 @@ static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t
|
||||||
expire_year++;
|
expire_year++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (expire_month != 0) { // Allow 0 if it signifies no expiration or error
|
} else if (expire_month != 0) { // Allow 0 if it signifies no expiration or error
|
||||||
PrintAndLogEx(WARNING, "Saflok: Invalid expiration month (%u) before day rollover.", expire_month);
|
PrintAndLogEx(WARNING, "Saflok: Invalid expiration month (%u) before day rollover", expire_month);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t checksum = decodedBA[16];
|
uint8_t checksum = decodedBA[16];
|
||||||
|
@ -326,19 +328,19 @@ static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t
|
||||||
bool checksum_valid = (checksum_calculated == checksum);
|
bool checksum_valid = (checksum_calculated == checksum);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Saflok Details"));
|
PrintAndLogEx(INFO, "--- " _CYAN_("SAFLOK details"));
|
||||||
PrintAndLogEx(SUCCESS, "Key Level: %u (%s)", saflok_key_levels[key_level].level_num, saflok_key_levels[key_level].level_name);
|
PrintAndLogEx(SUCCESS, "Key Level............. %u (%s)", saflok_key_levels[key_level].level_num, saflok_key_levels[key_level].level_name);
|
||||||
PrintAndLogEx(SUCCESS, "LED Warning: %s", led_warning ? "Yes" : "No");
|
PrintAndLogEx(SUCCESS, "LED Warning........... %s", led_warning ? "Yes" : "No");
|
||||||
PrintAndLogEx(SUCCESS, "Key ID: %u (0x%02X)", key_id, key_id);
|
PrintAndLogEx(SUCCESS, "Key ID................ %u (0x%02X)", key_id, key_id);
|
||||||
PrintAndLogEx(SUCCESS, "Key Record: %u (0x%04X)", key_record, key_record);
|
PrintAndLogEx(SUCCESS, "Key Record............ %u (0x%04X)", key_record, key_record);
|
||||||
PrintAndLogEx(SUCCESS, "Opening Key: %s", opening_key ? "Yes" : "No");
|
PrintAndLogEx(SUCCESS, "Opening Key........... %s", opening_key ? "Yes" : "No");
|
||||||
PrintAndLogEx(SUCCESS, "Sequence Number & Combination: %u (0x%02X)", sequence_combination_number, sequence_combination_number);
|
PrintAndLogEx(SUCCESS, "Sequence & Combination: %u (0x%02X)", sequence_combination_number, sequence_combination_number);
|
||||||
PrintAndLogEx(SUCCESS, "Override Deadbolt: %s", override_deadbolt ? "Yes" : "No");
|
PrintAndLogEx(SUCCESS, "Override Deadbolt..... %s", override_deadbolt ? "Yes" : "No");
|
||||||
PrintAndLogEx(SUCCESS, "Restricted Weekdays: %s", restricted_weekday_string);
|
PrintAndLogEx(SUCCESS, "Restricted Weekdays... %s", restricted_weekday_string);
|
||||||
PrintAndLogEx(SUCCESS, "Property ID: %u (0x%04X)", property_id, property_id);
|
PrintAndLogEx(SUCCESS, "Property ID........... %u (0x%04X)", property_id, property_id);
|
||||||
PrintAndLogEx(SUCCESS, "Creation Date: %04u-%02u-%02u %02u:%02u", creation_year, creation_month, creation_day, creation_hour, creation_minute);
|
PrintAndLogEx(SUCCESS, "Creation Date......... %04u-%02u-%02u %02u:%02u", creation_year, creation_month, creation_day, creation_hour, creation_minute);
|
||||||
PrintAndLogEx(SUCCESS, "Expiration Date: %04u-%02u-%02u %02u:%02u", expire_year, expire_month, expire_day, expiry_hour, expiry_minute);
|
PrintAndLogEx(SUCCESS, "Expiration Date....... %04u-%02u-%02u %02u:%02u", expire_year, expire_month, expire_day, expiry_hour, expiry_minute);
|
||||||
PrintAndLogEx(SUCCESS, "Checksum Valid: %s", checksum_valid ? "Yes" : "No");
|
PrintAndLogEx(SUCCESS, "Checksum Valid........ ( %s )", checksum_valid ? _GREEN_("ok") : _RED_("fail"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,20 +436,19 @@ static int initSectorTable(sector_t **src, size_t items) {
|
||||||
static void decode_print_st(uint16_t blockno, uint8_t *data) {
|
static void decode_print_st(uint16_t blockno, uint8_t *data) {
|
||||||
if (mfIsSectorTrailer(blockno)) {
|
if (mfIsSectorTrailer(blockno)) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Sector trailer decoder") " --------------------------");
|
PrintAndLogEx(INFO, "------------------------ " _CYAN_("Sector trailer decoder") " ------------------------");
|
||||||
PrintAndLogEx(INFO, "key A........ " _GREEN_("%s"), sprint_hex_inrow(data, 6));
|
PrintAndLogEx(INFO, " Key A........ " _BRIGHT_GREEN_("%s"), sprint_hex_inrow(data, 6));
|
||||||
PrintAndLogEx(INFO, "acr.......... " _GREEN_("%s"), sprint_hex_inrow(data + 6, 3));
|
PrintAndLogEx(INFO, " ACR.......... " _MAGENTA_("%s"), sprint_hex_inrow(data + 6, 3));
|
||||||
PrintAndLogEx(INFO, "user / gpb... " _GREEN_("%02x"), data[9]);
|
PrintAndLogEx(INFO, " User / gpb... %02x", data[9]);
|
||||||
PrintAndLogEx(INFO, "key B........ " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6));
|
PrintAndLogEx(INFO, " Key B........ " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6));
|
||||||
PrintAndLogEx(INFO, "");
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(INFO, " # | access rights");
|
PrintAndLogEx(INFO, " # | access rights");
|
||||||
PrintAndLogEx(INFO, "----+-----------------------------------------------------------------------");
|
PrintAndLogEx(INFO, "----+-------------------------------------------------------------------");
|
||||||
|
|
||||||
if (mfValidateAccessConditions(&data[6]) == false) {
|
if (mfValidateAccessConditions(&data[6]) == false) {
|
||||||
PrintAndLogEx(WARNING, _RED_("Invalid Access Conditions"));
|
PrintAndLogEx(WARNING, _RED_("Invalid access conditions"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int bln = mfFirstBlockOfSector(mfSectorNum(blockno));
|
int bln = mfFirstBlockOfSector(mfSectorNum(blockno));
|
||||||
int blinc = (mfNumBlocksPerSector(mfSectorNum(blockno)) > 4) ? 5 : 1;
|
int blinc = (mfNumBlocksPerSector(mfSectorNum(blockno)) > 4) ? 5 : 1;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
@ -458,13 +459,13 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) {
|
||||||
uint8_t cond = mf_get_accesscondition(i, &data[6]);
|
uint8_t cond = mf_get_accesscondition(i, &data[6]);
|
||||||
if (cond == 0 || cond == 1 || cond == 2) {
|
if (cond == 0 || cond == 1 || cond == 2) {
|
||||||
PrintAndLogEx(INFO, "");
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(INFO, "OBS! Key B is readable, it SHALL NOT be able to authenticate on original MFC");
|
PrintAndLogEx(INFO, "OBS!");
|
||||||
|
PrintAndLogEx(INFO, "Key B is readable, it SHALL NOT be able to authenticate on original MFC");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "------------------------------------------------------------------------");
|
||||||
PrintAndLogEx(INFO, "----------------------------------------------------------------------------");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +542,7 @@ void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) {
|
||||||
char ascii[24] = {0};
|
char ascii[24] = {0};
|
||||||
ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1);
|
ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"),
|
PrintAndLogEx(INFO, "%3d | " _BRIGHT_GREEN_("%s") _MAGENTA_("%s") "%02X " _GREEN_("%s") "| " _YELLOW_("%s"),
|
||||||
blockno,
|
blockno,
|
||||||
keya,
|
keya,
|
||||||
acl,
|
acl,
|
||||||
|
@ -1428,7 +1429,7 @@ static int CmdHF14AMfRdSc(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int keylen = 0;
|
int keylen = 0;
|
||||||
uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
uint8_t key[MIFARE_KEY_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
CLIGetHexWithReturn(ctx, 4, key, &keylen);
|
CLIGetHexWithReturn(ctx, 4, key, &keylen);
|
||||||
|
|
||||||
int s = arg_get_int_def(ctx, 5, 0);
|
int s = arg_get_int_def(ctx, 5, 0);
|
||||||
|
|
|
@ -29,15 +29,17 @@ define KNOWN_PLATFORM_DEFINITIONS
|
||||||
|
|
||||||
Known definitions:
|
Known definitions:
|
||||||
|
|
||||||
+============================================+
|
+==================================================+
|
||||||
| PLATFORM | DESCRIPTION |
|
| PLATFORM | DESCRIPTION |
|
||||||
+============================================+
|
+==================================================+
|
||||||
| PM3RDV4 (def) | Proxmark3 RDV4 |
|
| PM3RDV4 (def) | Proxmark3 RDV4 |
|
||||||
+--------------------------------------------+
|
+--------------------------------------------------+
|
||||||
| PM3GENERIC | Proxmark3 generic target |
|
| PM3GENERIC | Proxmark3 generic target |
|
||||||
+--------------------------------------------+
|
+--------------------------------------------------+
|
||||||
| PM3ICOPYX | iCopy-X with XC3S100E |
|
| PM3ICOPYX | iCopy-X with XC3S100E |
|
||||||
+--------------------------------------------+
|
+--------------------------------------------------+
|
||||||
|
| PM3ULTIMATE | Proxmark3 Ultimate with XC2S50 |
|
||||||
|
+--------------------------------------------------+
|
||||||
|
|
||||||
+============================================+
|
+============================================+
|
||||||
| PLATFORM_EXTRAS | DESCRIPTION |
|
| PLATFORM_EXTRAS | DESCRIPTION |
|
||||||
|
@ -153,7 +155,21 @@ else ifeq ($(PLATFORM),PM3ICOPYX)
|
||||||
PLATFORM_DEFS = -DWITH_FLASH -DICOPYX -DXC3
|
PLATFORM_DEFS = -DWITH_FLASH -DICOPYX -DXC3
|
||||||
PLTNAME = iCopy-X with XC3S100E
|
PLTNAME = iCopy-X with XC3S100E
|
||||||
PLATFORM_FPGA = xc3s100e
|
PLATFORM_FPGA = xc3s100e
|
||||||
|
else ifeq ($(PLATFORM),PM3ULTIMATE)
|
||||||
|
# FPGA bitstream files, the order doesn't matter anymore - only hf has a bitstream
|
||||||
|
FPGA_BITSTREAMS = fpga_pm3_ult_hf.bit
|
||||||
|
ifneq ($(SKIP_LF),1)
|
||||||
|
FPGA_BITSTREAMS += fpga_pm3_ult_lf.bit
|
||||||
|
endif
|
||||||
|
ifneq ($(SKIP_FELICA),1)
|
||||||
|
FPGA_BITSTREAMS += fpga_pm3_ult_felica.bit
|
||||||
|
endif
|
||||||
|
ifneq ($(SKIP_ISO15693),1)
|
||||||
|
FPGA_BITSTREAMS += fpga_pm3_ult_hf_15.bit
|
||||||
|
endif
|
||||||
|
PLATFORM_DEFS = -DWITH_FLASH -DXC2S50
|
||||||
|
PLTNAME = Proxmark3 Ultimate with XC2S50
|
||||||
|
PLATFORM_FPGA = xc2s50
|
||||||
else
|
else
|
||||||
$(error Invalid or empty PLATFORM: $(PLATFORM). $(KNOWN_DEFINITIONS))
|
$(error Invalid or empty PLATFORM: $(PLATFORM). $(KNOWN_DEFINITIONS))
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#if defined XC3
|
#if defined XC3
|
||||||
#define FPGA_TYPE "3s100evq100"
|
#define FPGA_TYPE "3s100evq100"
|
||||||
#define FPGA_CONFIG_SIZE 72864L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE
|
#define FPGA_CONFIG_SIZE 72864L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE
|
||||||
|
#elif defined XC2S50
|
||||||
|
#define FPGA_TYPE "2s50vq144"
|
||||||
|
#define FPGA_CONFIG_SIZE 69984L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE
|
||||||
#else
|
#else
|
||||||
#define FPGA_TYPE "2s30vq100"
|
#define FPGA_TYPE "2s30vq100"
|
||||||
#define FPGA_CONFIG_SIZE 42336L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE
|
#define FPGA_CONFIG_SIZE 42336L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE
|
||||||
|
|
|
@ -3695,7 +3695,8 @@
|
||||||
"hf iclass sim -t 2 -> execute loclass attack online part",
|
"hf iclass sim -t 2 -> execute loclass attack online part",
|
||||||
"hf iclass sim -t 3 -> simulate full iCLASS 2k tag",
|
"hf iclass sim -t 3 -> simulate full iCLASS 2k tag",
|
||||||
"hf iclass sim -t 4 -> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key",
|
"hf iclass sim -t 4 -> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key",
|
||||||
"hf iclass sim -t 6 -> simulate full iCLASS 2k tag that doesn't respond to r/w requests to the last SIO block"
|
"hf iclass sim -t 6 -> simulate full iCLASS 2k tag that doesn't respond to r/w requests to the last SIO block",
|
||||||
|
"hf iclass sim -t 7 -> simulate full iCLASS 2k tag that doesn't XOR or respond to r/w requests on block 3"
|
||||||
],
|
],
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
|
@ -13375,6 +13376,6 @@
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"commands_extracted": 768,
|
"commands_extracted": 768,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2025-06-07T09:11:06"
|
"extracted_on": "2025-06-08T07:56:09"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ At the moment both are maintained because they don't perfectly overlap yet.
|
||||||
|
|
||||||
| Feature | Makefile | Remarks |
|
| Feature | Makefile | Remarks |
|
||||||
|-----|---|---|
|
|-----|---|---|
|
||||||
| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC`, `PM3ICOPYX` |
|
| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC`, `PM3ICOPYX`, `PM3ULTIMATE` |
|
||||||
| Platform size | `PLATFORM_SIZE=` | values: `256`, `512` |
|
| Platform size | `PLATFORM_SIZE=` | values: `256`, `512` |
|
||||||
| Platform extras | `PLATFORM_EXTRAS=` | values: `BTADDON`, `FPC_USART_DEV` |
|
| Platform extras | `PLATFORM_EXTRAS=` | values: `BTADDON`, `FPC_USART_DEV` |
|
||||||
| Skip LF/HF techs in the firmware | `SKIP_`*`=1` | see `common_arm/Makefile.hal` for a list |
|
| Skip LF/HF techs in the firmware | `SKIP_`*`=1` | see `common_arm/Makefile.hal` for a list |
|
||||||
|
|
|
@ -62,10 +62,11 @@ For an up-to-date exhaustive list of options, you can run `make PLATFORM=`.
|
||||||
Here are the supported values you can assign to `PLATFORM` in `Makefile.platform`:
|
Here are the supported values you can assign to `PLATFORM` in `Makefile.platform`:
|
||||||
|
|
||||||
| PLATFORM | DESCRIPTION |
|
| PLATFORM | DESCRIPTION |
|
||||||
|-----------------|--------------------------|
|
|-----------------|-------------------------------|
|
||||||
| PM3RDV4 (def) | Proxmark3 RDV4 |
|
| PM3RDV4 (def) | Proxmark3 RDV4 |
|
||||||
| PM3GENERIC | Proxmark3 generic target |
|
| PM3GENERIC | Proxmark3 generic target |
|
||||||
| PM3ICOPYX | iCopy-X with XC3S100E |
|
| PM3ICOPYX | iCopy-X with XC3S100E |
|
||||||
|
| PM3ULTIMATE | Proxmar3 Ultimate with XC2S50 |
|
||||||
|
|
||||||
By default `PLATFORM=PM3RDV4`.
|
By default `PLATFORM=PM3RDV4`.
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
//`define PM3GENERIC
|
//`define PM3GENERIC
|
||||||
// iCopy-X with XC3S100E
|
// iCopy-X with XC3S100E
|
||||||
//`define PM3ICOPYX
|
//`define PM3ICOPYX
|
||||||
|
// Proxmark3 Ultimate with XC2S50
|
||||||
|
//`define PM3ULTIMATE
|
||||||
|
|
||||||
// Pass desired defines to compiler to enable required modules
|
// Pass desired defines to compiler to enable required modules
|
||||||
// WITH_LF enables Low Frequency mode when defined else HF is enabled
|
// WITH_LF enables Low Frequency mode when defined else HF is enabled
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue