Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
ry4000 2025-05-26 17:46:52 +10:00 committed by GitHub
commit 66c57e8652
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 1156 additions and 384 deletions

View file

@ -3,10 +3,17 @@ 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 `hf iclass dump` - now uses default AA1 key when called without a key or key index (@iceman1001)
- Renamed `hf iclass trbl` to `hf iclass tear` (@iceman1001)
- Changed `hw tearoff` - the device side message is now debug log controlled (@iceman1001)
- Changed `pm3.sh` - Serial ports enumeration on Proxspace3.xx / MINGW environments, now using powershell.exe since wmic is deprecated (@iceman1001)
- Fixed and updated `hf iclass trbl` to correctly use the credit key when passed and show partial tearoff results (@antiklesys)
- Fixed `hf iclass legbrute` was not correctly parsin the index value
- Fixed `hf mf ekeyprn` - failed to download emulator memory due to wrong size calculation (@iceman1001)
- Fixed `hf mf fchk --mem` to actually use flash dict (@doegox)
- Fixed `make install` on OSX thanks DaveItsLong (@doegox)
- Added new standalone mode `HF_ST25_TEAROFF` to store/restore ST25TB tags with tearoff for counters (@seclabz)
- Added `hf_mfu_ultra.lua` script enables restoring dump to ULTRA/UL-5 tags and clearing previously written ULTRA tags (@mak-42)
## [Blue Ice.4.20142][2025-03-25]
- Added `des_talk.py` script for easier MIFARE DESFire handling (@trigat)
@ -44,7 +51,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Changed `hf mf cload` - now accepts MFC Ev1 sized dumps (@iceman1001)
- Changed `hf mfu info` - now properly identify ULEv1 AES 50pF (@iceman1001)
- Changed `hf mf info` - now differentiates between full USCUID and cut down ZUID chips (@nvx)
- Changed `lf hitag chk` - added key counter, client side abort and minor delay (@iceman1001)
- Changed `lf hitag chk` - added key counter, client side abort and minor delay (@iceman1001)
- Added `hf seos sam` - Added support for HID SAM SEOS communications (@jkramarz)
- Changed (extended) area accessible by spiffs into last page of FLASH (@piotrva)
- Changed flash-stored key dictionaries (Mifare, iClass, T55XX) and T55XX configurations to SPIFFS files (@piotrva)

View file

@ -27,6 +27,10 @@ PLATFORM=PM3RDV4
# Only available with PLATFORM=PM3GENERIC
#LED_ORDER=PM3EASY
# Uncomment a line below to change default USART baud rate
# defaults to 115200 used by HC-05 in Blueshark
#USART_BAUD_RATE=19200
# Uncomment the lines below in order to make a 256KB image
# and comment out the lines above

View file

@ -121,7 +121,7 @@ void BigBuf_Clear_ext(bool verbose) {
memset(BigBuf, 0, s_bigbuf_size);
clear_trace();
if (verbose) {
Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size);
if (g_dbglevel >= DBG_ERROR) Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size);
}
}

View file

@ -252,7 +252,7 @@ static void update_leds_mode(standalone_mode_t mode) {
*/
static void indicate_success(void) {
// Blink Green LED (A) 3 times quickly for success
for(int i=0; i<3; ++i) {
for (int i = 0; i < 3; ++i) {
LED_A_ON();
SpinDelay(150);
LED_A_OFF();
@ -265,7 +265,7 @@ static void indicate_success(void) {
*/
static void indicate_failure(void) {
// Blink Red LED (B) 3 times quickly for failure
for(int i=0; i<3; ++i) {
for (int i = 0; i < 3; ++i) {
LED_B_ON();
SpinDelay(150);
LED_B_OFF();
@ -291,7 +291,7 @@ static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]) {
// Verify file size
uint32_t size = size_in_spiffs(HF_ST25TB_MULTI_SR_FILE);
if (size != sizeof(g_stored_tags)) {
Dbprintf(_RED_("Flash file size mismatch (expected %zu, got %u). Wiping old file."),
Dbprintf(_RED_("Flash file size mismatch (expected %zu, got %u). Wiping old file."),
sizeof(g_stored_tags), size);
// Remove corrupted file
rdv40_spiffs_remove(HF_ST25TB_MULTI_SR_FILE, RDV40_SPIFFS_SAFETY_SAFE);
@ -299,8 +299,8 @@ static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]) {
}
// Read file contents
int res = rdv40_spiffs_read(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection,
size, RDV40_SPIFFS_SAFETY_SAFE);
int res = rdv40_spiffs_read(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection,
size, RDV40_SPIFFS_SAFETY_SAFE);
if (res != SPIFFS_OK) {
Dbprintf(_RED_("Failed to read tag collection from flash (err %d)"), res);
@ -319,8 +319,8 @@ static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]) {
* @return true if successful, false otherwise
*/
static bool save_tags_to_flash(const st25tb_data_t collection[MAX_SAVED_TAGS]) {
int res = rdv40_spiffs_write(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection,
sizeof(g_stored_tags), RDV40_SPIFFS_SAFETY_SAFE);
int res = rdv40_spiffs_write(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection,
sizeof(g_stored_tags), RDV40_SPIFFS_SAFETY_SAFE);
return (res == SPIFFS_OK);
}
@ -356,7 +356,7 @@ static int find_free_tag_slot(void) {
//=============================================================================
/**
* @brief Stripped version of "iso14443b_setup" that avoids unnecessary LED
* @brief Stripped version of "iso14443b_setup" that avoids unnecessary LED
* operations and uses shorter delays
*/
static void iso14443b_setup_light(void) {
@ -417,7 +417,7 @@ static bool st25tb_tag_read(st25tb_data_t *tag_data_slot) {
Dbprintf("Found ST tag. Reading %d blocks...", ST25TB_BLOCK_COUNT);
tag_data_slot->uid = bytes_to_num_le(card_info.uid, sizeof(tag_data_slot->uid));
// Read all data blocks
for (uint8_t block_address = 0; block_address < ST25TB_BLOCK_COUNT; block_address++) {
WDT_HIT();
@ -507,7 +507,7 @@ static bool st25tb_tag_restore(const st25tb_data_t *stored_data_slot) {
}
if (g_dbglevel >= DBG_DEBUG) {
Dbprintf("Counter Block %d: Stored=0x%08X, Current=0x%08X",
Dbprintf("Counter Block %d: Stored=0x%08X, Current=0x%08X",
block_address, stored_value, current_value);
}
@ -528,7 +528,7 @@ static bool st25tb_tag_restore(const st25tb_data_t *stored_data_slot) {
break;
}
} else {
Dbprintf("Counter block %d already has the target value (0x%08X). Skipping write.",
Dbprintf("Counter block %d already has the target value (0x%08X). Skipping write.",
block_address, stored_value);
}
} else {
@ -658,7 +658,7 @@ static void st25tb_tear_off_write_block(uint8_t block_address, uint32_t data, ui
block[0] = (data & 0xFF);
block[1] = (data >> 8) & 0xFF;
block[2] = (data >> 16) & 0xFF;
block[3] = (data >> 24) & 0xFF;
block[3] = (data >> 24) & 0xFF;
iso14b_card_select_t card;
int res = iso14443b_select_srx_card(&card);
@ -667,7 +667,7 @@ static void st25tb_tear_off_write_block(uint8_t block_address, uint32_t data, ui
}
res = st25tb_cmd_write_block(block_address, block);
// Tear off the communication at precise timing
SpinDelayUsPrecision(tearoff_delay_us);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -685,9 +685,9 @@ out:
* @param read_back_value Pointer to store read-back value
* @return 0 for success, -1 for failure
*/
static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t target_value,
uint32_t max_try_count, int sleep_time_ms,
uint32_t *read_back_value) {
static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t target_value,
uint32_t max_try_count, int sleep_time_ms,
uint32_t *read_back_value) {
int i = 0;
*read_back_value = ~target_value; // Initialize to ensure the loop runs at least once
@ -711,9 +711,9 @@ static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t
* @param read_value Pointer to store read value
* @return 0 if consolidated, -1 otherwise
*/
static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint32_t value,
int repeat_read, int sleep_time_ms,
uint32_t *read_value) {
static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint32_t value,
int repeat_read, int sleep_time_ms,
uint32_t *read_value) {
int result;
for (int i = 0; i < repeat_read; i++) {
if (sleep_time_ms > 0) SpinDelayUsPrecision(sleep_time_ms * 1000);
@ -733,8 +733,8 @@ static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint3
* @param read_back_value Pointer to store read-back value
* @return 0 for success, -1 for failure
*/
static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uint32_t current_value,
uint32_t target_value, uint32_t *read_back_value) {
static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uint32_t current_value,
uint32_t target_value, uint32_t *read_back_value) {
int8_t result;
uint32_t consolidation_value;
@ -746,8 +746,8 @@ static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uin
}
// Try writing value - 1
result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 1,
TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value);
result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 1,
TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value);
if (result != 0) {
Dbprintf("Consolidation failed at step 1 (write 0x%08X)", consolidation_value - 1);
return -1;
@ -755,8 +755,8 @@ static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uin
// If value is not FE or target is not FD, try writing value - 2
if (*read_back_value != 0xFFFFFFFE || (*read_back_value == 0xFFFFFFFE && target_value == 0xFFFFFFFD)) {
result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 2,
TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value);
result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 2,
TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value);
if (result != 0) {
Dbprintf("Consolidation failed at step 2 (write 0x%08X)", consolidation_value - 2);
return -1;
@ -765,12 +765,12 @@ static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uin
// Final checks for stability of unstable high values (due to internal dual counters)
if (result == 0 && target_value > 0xFFFFFFFD && *read_back_value > 0xFFFFFFFD) {
result = st25tb_tear_off_is_consolidated(block_address, *read_back_value,
TEAR_OFF_CONSOLIDATE_READ_COUNT, 0, read_back_value);
result = st25tb_tear_off_is_consolidated(block_address, *read_back_value,
TEAR_OFF_CONSOLIDATE_READ_COUNT, 0, read_back_value);
if (result == 0) {
result = st25tb_tear_off_is_consolidated(block_address, *read_back_value,
TEAR_OFF_CONSOLIDATE_WAIT_READ_COUNT,
TEAR_OFF_CONSOLIDATE_WAIT_MS, read_back_value);
result = st25tb_tear_off_is_consolidated(block_address, *read_back_value,
TEAR_OFF_CONSOLIDATE_WAIT_READ_COUNT,
TEAR_OFF_CONSOLIDATE_WAIT_MS, read_back_value);
if (result != 0) {
Dbprintf("Consolidation failed stability check (long wait)");
return -1;
@ -861,8 +861,8 @@ static void st25tb_tear_off_log(int tear_off_us, char *color, uint32_t value) {
* @param safety_value Safety threshold to prevent going below
* @return 0 for success, non-zero for failure
*/
static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t target_value,
uint32_t tear_off_adjustment_us, uint32_t safety_value) {
static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t target_value,
uint32_t tear_off_adjustment_us, uint32_t safety_value) {
int result;
bool trigger = true;
@ -906,7 +906,7 @@ static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t targ
for (;;) {
// Safety check: ensure we don't go below the safety threshold
if (tear_off_value < safety_value) {
Dbprintf("Stopped. Safety threshold reached (next value 0x%08X < safety 0x%08X)",
Dbprintf("Stopped. Safety threshold reached (next value 0x%08X < safety 0x%08X)",
tear_off_value, safety_value);
return -1;
}
@ -921,15 +921,15 @@ static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t targ
}
// Analyze the result and decide next action
if (read_value > current_value) {
if (read_value > current_value) {
// Partial write succeeded (successful tear-off)
if (read_value >= 0xFFFFFFFE ||
(read_value - 2) > target_value ||
read_value != last_consolidated_value ||
((read_value & 0xF0000000) > (current_value & 0xF0000000))) { // Major bit flip
result = st25tb_tear_off_consolidate_block(block_address, read_value,
target_value, &current_value);
(read_value - 2) > target_value ||
read_value != last_consolidated_value ||
((read_value & 0xF0000000) > (current_value & 0xF0000000))) { // Major bit flip
result = st25tb_tear_off_consolidate_block(block_address, read_value,
target_value, &current_value);
if (result == 0 && current_value == target_value) {
st25tb_tear_off_log(tear_off_us, GREEN, read_value);
Dbprintf("Target value 0x%08X reached successfully!", target_value);
@ -1004,11 +1004,11 @@ static void run_learn_function(void) {
} else {
// Only increment if we are adding to a new slot, not overwriting
if (!g_stored_tags[slot_index].data_valid) {
g_valid_tag_count++;
g_valid_tag_count++;
}
}
}
// Store tag data in collection
memcpy(&g_stored_tags[slot_index], &temp_tag_data, sizeof(st25tb_data_t));
g_stored_tags[slot_index].data_valid = true;
@ -1020,7 +1020,7 @@ static void run_learn_function(void) {
} else {
DbpString(_RED_("Failed to save collection to flash!"));
}
current_state = STATE_DONE; // Indicate success
}
}
@ -1052,8 +1052,8 @@ static void run_restore_function(void) {
current_state = STATE_ERROR;
}
} else {
// Tag found but not in collection, remain busy to scan again
current_state = STATE_BUSY;
// Tag found but not in collection, remain busy to scan again
current_state = STATE_BUSY;
}
} else {
// No tag found, remain busy to scan again
@ -1131,10 +1131,10 @@ void RunMod(void) {
// --- Update Display (only if mode changed) ---
if (mode_display_update) {
if (g_current_mode == MODE_LEARN) {
Dbprintf("Mode: " _YELLOW_("Learn") ". (Cnt: %d/%d)",
Dbprintf("Mode: " _YELLOW_("Learn") ". (Cnt: %d/%d)",
g_valid_tag_count, MAX_SAVED_TAGS);
} else {
Dbprintf("Mode: " _BLUE_("Restore") ". (Cnt: %d/%d)",
Dbprintf("Mode: " _BLUE_("Restore") ". (Cnt: %d/%d)",
g_valid_tag_count, MAX_SAVED_TAGS);
}
mode_display_update = false;
@ -1142,14 +1142,14 @@ void RunMod(void) {
update_leds_mode(g_current_mode);
// Process according to current state
if(current_state == STATE_BUSY) {
if (current_state == STATE_BUSY) {
// Run appropriate function based on mode
if (g_current_mode == MODE_LEARN) {
run_learn_function();
} else { // MODE_RESTORE
run_restore_function();
}
} else if(current_state == STATE_DONE) {
} else if (current_state == STATE_DONE) {
indicate_success();
} else {
indicate_failure();

View file

@ -104,7 +104,7 @@ int tearoff_hook(void) {
SpinDelayUsPrecision(g_tearoff_delay_us);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
g_tearoff_enabled = false;
Dbprintf(_YELLOW_("Tear-off triggered!"));
if (g_dbglevel >= DBG_ERROR) Dbprintf(_YELLOW_("Tear-off triggered!"));
return PM3_ETEAROFF;
} else {
return PM3_SUCCESS; // SUCCESS = the hook didn't do anything
@ -254,7 +254,7 @@ static uint32_t MeasureAntennaTuningLfData(void) {
void print_stack_usage(void) {
for (uint32_t *p = _stack_start; ; ++p) {
if (*p != 0xdeadbeef) {
Dbprintf(" Max stack usage......... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start);
Dbprintf(" Max stack usage..... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start);
break;
}
}
@ -365,7 +365,7 @@ static void print_debug_level(void) {
sprintf(dbglvlstr, "extended");
break;
}
Dbprintf(" Debug log level......... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr);
Dbprintf(" Debug log level..... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr);
}
// measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time.
@ -421,11 +421,11 @@ static void SendStatus(uint32_t wait) {
print_debug_level();
tosend_t *ts = get_tosend();
Dbprintf(" ToSendMax............... %d", ts->max);
Dbprintf(" ToSend BUFFERSIZE....... %d", TOSEND_BUFFER_SIZE);
Dbprintf(" ToSendMax........... %d", ts->max);
Dbprintf(" ToSend BUFFERSIZE... %d", TOSEND_BUFFER_SIZE);
while ((AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINRDY) == 0); // Wait for MAINF value to become available...
uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINF; // Get # main clocks within 16 slow clocks
Dbprintf(" Slow clock.............. %d Hz", (16 * MAINCK) / mainf);
Dbprintf(" Slow clock.......... %d Hz", (16 * MAINCK) / mainf);
uint32_t delta_time = 0;
uint32_t start_time = GetTickCount();
#define SLCK_CHECK_MS 50
@ -449,10 +449,11 @@ static void SendStatus(uint32_t wait) {
} else {
num = 0;
}
if (num > 0) {
Dbprintf(" Mifare.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, MF_KEYS_FILE);
Dbprintf(" Mifare... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MF_KEYS_FILE);
} else {
Dbprintf(" Mifare.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, MF_KEYS_FILE);
Dbprintf(" Mifare... "_RED_("%u")" keys - "_RED_("%s"), num, MF_KEYS_FILE);
}
if (exists_in_spiffs(T55XX_KEYS_FILE)) {
@ -460,10 +461,11 @@ static void SendStatus(uint32_t wait) {
} else {
num = 0;
}
if (num > 0) {
Dbprintf(" T55xx................... "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, T55XX_KEYS_FILE);
Dbprintf(" T55xx.... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, T55XX_KEYS_FILE);
} else {
Dbprintf(" T55xx................... "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, T55XX_KEYS_FILE);
Dbprintf(" T55xx.... "_RED_("%u")" keys - "_RED_("%s"), num, T55XX_KEYS_FILE);
}
if (exists_in_spiffs(ICLASS_KEYS_FILE)) {
@ -471,10 +473,11 @@ static void SendStatus(uint32_t wait) {
} else {
num = 0;
}
if (num > 0) {
Dbprintf(" iClass.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, ICLASS_KEYS_FILE);
Dbprintf(" iClass... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, ICLASS_KEYS_FILE);
} else {
Dbprintf(" iClass.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, ICLASS_KEYS_FILE);
Dbprintf(" iClass... "_RED_("%u")" keys - "_RED_("%s"), num, ICLASS_KEYS_FILE);
}
#endif
DbpString("");
@ -2354,7 +2357,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint16_t available;
uint16_t pre_available = 0;
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
uint8_t *dest = BigBuf_calloc(USART_FIFOLEN);
uint32_t wait = payload->waittime;
StartTicks();
@ -2398,7 +2401,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint16_t available;
uint16_t pre_available = 0;
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
uint8_t *dest = BigBuf_calloc(USART_FIFOLEN);
uint32_t wait = payload->waittime;
StartTicks();
@ -2694,7 +2697,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint32_t size = packet->oldarg[1];
uint8_t *buff = BigBuf_malloc(size);
uint8_t *buff = BigBuf_calloc(size);
if (buff == NULL) {
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Failed to allocate memory");
// Trigger a finish downloading signal with an PM3_EMALLOC
@ -2899,7 +2902,7 @@ static void PacketReceived(PacketCommandNG *packet) {
case CMD_FLASHMEM_DOWNLOAD: {
LED_B_ON();
uint8_t *mem = BigBuf_malloc(PM3_CMD_DATA_SIZE);
uint8_t *mem = BigBuf_calloc(PM3_CMD_DATA_SIZE);
uint32_t startidx = packet->oldarg[0];
uint32_t numofbytes = packet->oldarg[1];
// arg0 = startindex
@ -2931,7 +2934,7 @@ static void PacketReceived(PacketCommandNG *packet) {
case CMD_FLASHMEM_INFO: {
LED_B_ON();
rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_malloc(sizeof(rdv40_validation_t));
rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_calloc(sizeof(rdv40_validation_t));
bool isok = Flash_ReadData(FLASH_MEM_SIGNATURE_OFFSET_P(spi_flash_pages64k), info->signature, FLASH_MEM_SIGNATURE_LEN);

View file

@ -748,7 +748,7 @@ void em4x50_chk(const char *filename, bool ledcontrol) {
uint16_t pwd_count = 0;
uint32_t size = size_in_spiffs(filename);
pwd_count = size / 4;
uint8_t *pwds = BigBuf_malloc(size);
uint8_t *pwds = BigBuf_calloc(size);
rdv40_spiffs_read_as_filetype(filename, pwds, size, RDV40_SPIFFS_SAFETY_SAFE);

View file

@ -857,7 +857,7 @@ void SmartCardRaw(const smart_card_raw_t *p) {
LED_D_ON();
uint16_t len = 0;
uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
// check if alloacted...
smartcard_command_t flags = p->flags;
@ -937,7 +937,7 @@ void SmartCardUpgrade(uint64_t arg0) {
bool isOK = true;
uint16_t length = arg0, pos = 0;
const uint8_t *fwdata = BigBuf_get_addr();
uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE);
uint8_t *verfiydata = BigBuf_calloc(I2C_BLOCK_SIZE);
while (length) {

View file

@ -40,7 +40,7 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
LED_D_ON();
uint16_t len = 0;
uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
resp[0] = prepend;
// check if alloacted...
smartcard_command_t flags = p->flags;

View file

@ -399,40 +399,40 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) {
int trace_data_size;
// Respond SOF -- takes 1 bytes
uint8_t *resp_sof = BigBuf_malloc(1);
uint8_t resp_sof[1] = {0};
int resp_sof_len;
// Anticollision CSN (rotated CSN)
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
uint8_t *resp_anticoll = BigBuf_malloc(22);
uint8_t *resp_anticoll = BigBuf_calloc(22);
int resp_anticoll_len;
// CSN (block 0)
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
uint8_t *resp_csn = BigBuf_malloc(22);
uint8_t *resp_csn = BigBuf_calloc(22);
int resp_csn_len;
// configuration (blk 1) PICOPASS 2ks
uint8_t *resp_conf = BigBuf_malloc(22);
uint8_t *resp_conf = BigBuf_calloc(22);
int resp_conf_len;
// e-Purse (blk 2)
// 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit)
uint8_t *resp_cc = BigBuf_malloc(18);
uint8_t *resp_cc = BigBuf_calloc(18);
int resp_cc_len;
// Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only
uint8_t *resp_ff = BigBuf_malloc(22);
uint8_t *resp_ff = BigBuf_calloc(22);
int resp_ff_len;
uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00};
AddCrc(ff_data, 8);
// Application Issuer Area (blk 5)
uint8_t *resp_aia = BigBuf_malloc(22);
uint8_t *resp_aia = BigBuf_calloc(22);
int resp_aia_len;
// receive command
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
// Prepare card messages
tosend_t *ts = get_tosend();
@ -474,11 +474,11 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) {
//This is used for responding to READ-block commands or other data which is dynamically generated
//First the 'trace'-data, not encoded for FPGA
uint8_t *data_generic_trace = BigBuf_malloc(34); // 32 bytes data + 2byte CRC is max tag answer
uint8_t *data_generic_trace = BigBuf_calloc(34); // 32 bytes data + 2byte CRC is max tag answer
//Then storage for the modulated data
//Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes)
uint8_t *data_response = BigBuf_malloc((34 * 2) + 3);
uint8_t *data_response = BigBuf_calloc((34 * 2) + 3);
enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE;
@ -942,29 +942,29 @@ int do_iclass_simulation_nonsec(void) {
int trace_data_size = 0;
// Respond SOF -- takes 1 bytes
uint8_t *resp_sof = BigBuf_malloc(2);
uint8_t resp_sof[2] = { 0 };
int resp_sof_len;
// Anticollision CSN (rotated CSN)
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
uint8_t *resp_anticoll = BigBuf_malloc(28);
uint8_t *resp_anticoll = BigBuf_calloc(28);
int resp_anticoll_len;
// CSN
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
uint8_t *resp_csn = BigBuf_malloc(28);
uint8_t *resp_csn = BigBuf_calloc(28);
int resp_csn_len;
// configuration (blk 1) PICOPASS 2ks
uint8_t *resp_conf = BigBuf_malloc(28);
uint8_t *resp_conf = BigBuf_calloc(28);
int resp_conf_len;
// Application Issuer Area (blk 5)
uint8_t *resp_aia = BigBuf_malloc(28);
uint8_t *resp_aia = BigBuf_calloc(28);
int resp_aia_len;
// receive command
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
// Prepare card messages
tosend_t *ts = get_tosend();
@ -997,11 +997,11 @@ int do_iclass_simulation_nonsec(void) {
//This is used for responding to READ-block commands or other data which is dynamically generated
//First the 'trace'-data, not encoded for FPGA
uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer
uint8_t *data_generic_trace = BigBuf_calloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer
//Then storage for the modulated data
//Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes)
uint8_t *data_response = BigBuf_malloc((32 + 2) * 2 + 2);
uint8_t *data_response = BigBuf_calloc((32 + 2) * 2 + 2);
enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE;

View file

@ -190,35 +190,35 @@ struct Crypto1State crypto1_state = {0, 0};
void printHf14aConfig(void) {
DbpString(_CYAN_("HF 14a config"));
Dbprintf(" [a] Anticol override.............. %s%s%s",
Dbprintf(" [a] Anticol override........... %s%s%s",
(hf14aconfig.forceanticol == 0) ? _GREEN_("std") " ( follow standard )" : "",
(hf14aconfig.forceanticol == 1) ? _RED_("force") " ( always do anticol )" : "",
(hf14aconfig.forceanticol == 2) ? _RED_("skip") " ( always skip anticol )" : ""
);
Dbprintf(" [b] BCC override.................. %s%s%s",
Dbprintf(" [b] BCC override............... %s%s%s",
(hf14aconfig.forcebcc == 0) ? _GREEN_("std") " ( follow standard )" : "",
(hf14aconfig.forcebcc == 1) ? _RED_("fix") " ( fix bad BCC )" : "",
(hf14aconfig.forcebcc == 2) ? _RED_("ignore") " ( ignore bad BCC, always use card BCC )" : ""
);
Dbprintf(" [2] CL2 override.................. %s%s%s",
Dbprintf(" [2] CL2 override............... %s%s%s",
(hf14aconfig.forcecl2 == 0) ? _GREEN_("std") " ( follow standard )" : "",
(hf14aconfig.forcecl2 == 1) ? _RED_("force") " ( always do CL2 )" : "",
(hf14aconfig.forcecl2 == 2) ? _RED_("skip") " ( always skip CL2 )" : ""
);
Dbprintf(" [3] CL3 override.................. %s%s%s",
Dbprintf(" [3] CL3 override............... %s%s%s",
(hf14aconfig.forcecl3 == 0) ? _GREEN_("std") " ( follow standard )" : "",
(hf14aconfig.forcecl3 == 1) ? _RED_("force") " ( always do CL3 )" : "",
(hf14aconfig.forcecl3 == 2) ? _RED_("skip") " ( always skip CL3 )" : ""
);
Dbprintf(" [r] RATS override................. %s%s%s",
Dbprintf(" [r] RATS override.............. %s%s%s",
(hf14aconfig.forcerats == 0) ? _GREEN_("std") " ( follow standard )" : "",
(hf14aconfig.forcerats == 1) ? _RED_("force") " ( always do RATS )" : "",
(hf14aconfig.forcerats == 2) ? _RED_("skip") " ( always skip RATS )" : ""
);
Dbprintf(" [m] Magsafe polling............... %s",
Dbprintf(" [m] Magsafe polling............ %s",
(hf14aconfig.magsafe == 1) ? _GREEN_("enabled") : _YELLOW_("disabled")
);
Dbprintf(" [p] Polling loop annotation....... %s %*D",
Dbprintf(" [p] Polling loop annotation.... %s %*D",
(hf14aconfig.polling_loop_annotation.frame_length <= 0) ? _YELLOW_("disabled") : _GREEN_("enabled"),
hf14aconfig.polling_loop_annotation.frame_length,
hf14aconfig.polling_loop_annotation.frame,
@ -524,6 +524,7 @@ RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) {
Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit
Uart.bitCount = 0;
Uart.shiftReg = 0;
// Every 8 data bytes, store 8 parity bits into a parity byte
if ((Uart.len & 0x0007) == 0) { // every 8 data bytes
Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits
@ -804,12 +805,12 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
set_tracing(true);
// The command (reader -> tag) that we're receiving.
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
uint8_t *receivedCmdPar = BigBuf_calloc(MAX_PARITY_SIZE);
// The response (tag -> reader) that we're receiving.
uint8_t *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE);
uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *receivedResp = BigBuf_calloc(MAX_FRAME_SIZE);
uint8_t *receivedRespPar = BigBuf_calloc(MAX_PARITY_SIZE);
uint8_t previous_data = 0;
int maxDataLen = 0, dataLen;
@ -1496,6 +1497,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
// "precompiled" responses.
// These exist for speed reasons. There are no time in the anti collision phase to calculate responses.
// There are 12 predefined responses with a total of 84 bytes data to transmit.
//
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 85 * 8 data bits, 85 * 1 parity bits, 12 start bits, 12 stop bits, 12 correction bits
// 85 * 8 + 85 + 12 + 12 + 12 == 801
@ -2681,9 +2683,9 @@ void iso14443a_antifuzz(uint32_t flags) {
int len = 0;
// allocate buffers:
uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE);
uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *resp = BigBuf_malloc(20);
uint8_t *received = BigBuf_calloc(MAX_FRAME_SIZE);
uint8_t *receivedPar = BigBuf_calloc(MAX_PARITY_SIZE);
uint8_t *resp = BigBuf_calloc(20);
memset(received, 0x00, MAX_FRAME_SIZE);
memset(received, 0x00, MAX_PARITY_SIZE);
@ -2771,19 +2773,19 @@ static void iso14a_set_ATS_times(const uint8_t *ats) {
static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const iso14a_polling_parameters_t *polling_parameters) {
#define RETRY_TIMEOUT 10
#define RETRY_TIMEOUT 10
uint32_t save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(1236 / 128 + 1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer.
// refactored to use local pointer, now no modification of polling_parameters pointer is done
// I don't think the intention was to modify polling_parameters when sending in WUPA_POLLING_PARAMETERS etc.
// I don't think the intention was to modify polling_parameters when sending in WUPA_POLLING_PARAMETERS etc.
// Modify polling_params, if null use default values.
iso14a_polling_parameters_t p;
memcpy(&p, (uint8_t*)polling_parameters, sizeof(iso14a_polling_parameters_t));
memcpy(&p, (uint8_t *)polling_parameters, sizeof(iso14a_polling_parameters_t));
if (polling_parameters == NULL) {
memcpy(&p, (uint8_t*)&hf14a_polling_parameters, sizeof(iso14a_polling_parameters_t));
memcpy(&p, (uint8_t *)&hf14a_polling_parameters, sizeof(iso14a_polling_parameters_t));
}
bool first_try = true;
@ -4068,9 +4070,7 @@ void DetectNACKbug(void) {
// i = number of authentications sent. Not always 256, since we are trying to sync but close to it.
FpgaDisableTracing();
uint8_t *data = BigBuf_malloc(4);
data[0] = isOK;
data[1] = num_nacks;
uint8_t data[4] = {isOK, num_nacks, 0, 0};
num_to_bytes(i, 2, data + 2);
reply_ng(CMD_HF_MIFARE_NACK_DETECT, status, data, 4);

View file

@ -221,10 +221,11 @@ out:
int sam_get_version(void) {
int res = PM3_SUCCESS;
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("start sam_get_version");
}
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
uint16_t response_len = ISO7816_MAX_FRAME;
uint8_t payload[] = {
@ -252,8 +253,9 @@ int sam_get_version(void) {
// 82 01
// 01
// 90 00
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("end sam_get_version");
}
if (response[5] != 0xbd) {
Dbprintf("Invalid SAM response");
@ -289,8 +291,9 @@ error:
out:
BigBuf_free();
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("end sam_get_version");
}
return res;
}
@ -350,12 +353,10 @@ void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type
}
void sam_send_ack(void) {
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
uint16_t response_len = ISO7816_MAX_FRAME;
uint8_t payload[] = {
0xa0, 0
};
uint8_t payload[] = { 0xa0, 0 };
uint16_t payload_len = sizeof(payload);
sam_send_payload(

View file

@ -46,11 +46,12 @@
*/
static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod, const bool break_on_nr_mac, const bool prevent_epurse_update) {
int res = PM3_SUCCESS;
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("start sam_send_request_iso14a");
}
uint8_t *buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *buf1 = BigBuf_calloc(ISO7816_MAX_FRAME);
uint8_t *buf2 = BigBuf_calloc(ISO7816_MAX_FRAME);
if (buf1 == NULL || buf2 == NULL) {
res = PM3_EMALLOC;
goto out;
@ -255,10 +256,10 @@ out:
*/
static int sam_set_card_detected_picopass(const picopass_hdr_t *card_select) {
int res = PM3_SUCCESS;
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("start sam_set_card_detected");
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
}
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
uint16_t response_len = ISO7816_MAX_FRAME;
// a0 12
@ -314,8 +315,9 @@ error:
out:
BigBuf_free();
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("end sam_set_card_detected");
}
return res;
}

View file

@ -51,13 +51,14 @@
*/
static int sam_set_card_detected_seos(iso14a_card_select_t *card_select) {
int res = PM3_SUCCESS;
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("start sam_set_card_detected");
}
uint8_t *request = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *request = BigBuf_calloc(ISO7816_MAX_FRAME);
uint16_t request_len = ISO7816_MAX_FRAME;
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
uint16_t response_len = ISO7816_MAX_FRAME;
const uint8_t payload[] = {
@ -107,8 +108,9 @@ error:
out:
BigBuf_free();
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
DbpString("end sam_set_card_detected");
}
return res;
}

View file

@ -312,7 +312,7 @@ static int is_valid_filename(const char *filename) {
*/
static void copy_in_spiffs(const char *src, const char *dst) {
uint32_t size = size_in_spiffs(src);
uint8_t *mem = BigBuf_malloc(size);
uint8_t *mem = BigBuf_calloc(size);
read_from_spiffs(src, (uint8_t *)mem, size);
write_to_spiffs(dst, (uint8_t *)mem, size);
}

View file

@ -3107,3 +3107,55 @@ AB921CF0752C
265A5F32DE73
567D734C403C
2426217B3B3B
#
# Card keys from Andalusian public transport system (Consorcio de Transportes)
1848A8D1E4C5
16EE1FE134E4
5246B8F4ACFC
515A8209843C
0EF7636AA829
E59D0F78C413
5AF68604DD6B
B0BCB22DCBA3
51B3EF60BF56
99100225D83B
63C88F562B97
B30B6A5AD434
D33E4A4A0041
9C0A4CC89D61
5204D83D8CD3
A662F9DC0D3D
#
# Card keys from EMT Malaga (Spain) bus system
41534E354936
454D41343253
4541444C4130
46305234324E
505444505232
5239425A3546
454449434631
414F4544384C
344E4F4E4937
45444E413254
3255534D3033
4F554D523935
3141544D3735
494E47463539
32414F4E3341
41534C473637
534E41395430
41364C38364F
525241414D39
41304532334F
4D4545494F35
4E324C453045
394143494E32
5352554E3245
324553553036
444D414E3539
324745413232
4E4E41455236
394C52493639
4D4941413236
414D504F3243
434C414E3639

View file

@ -0,0 +1,357 @@
local ansicolors = require('ansicolors')
local cmds = require('commands')
local getopt = require('getopt')
local lib14a = require('read14a')
local utils = require('utils')
-- globals
copyright = ''
author = 'Dmitry Malenok'
version = 'v1.0.0'
desc = [[
The script provides functionality for writing Mifare Ultralight Ultra/UL-5 tags.
]]
example = [[
-- restpre (write) dump to tag
]]..ansicolors.yellow..[[script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r]]..ansicolors.reset..[[
-- wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[)
]]..ansicolors.yellow..[[script run hf_mfu_ultra -k 1d237f76 -w ]]..ansicolors.reset..[[
]]
usage = [[
script run hf_mfu_ultra -h -f <dump filename> -k <passwd> -w -r
]]
arguments = [[
-h this help
-f filename for the datadump to read (bin)
-k pwd to use with the restore and wipe operations
-r restore a binary dump to tag
-w wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[)
]]
local _password = nil
local _defaultPassword = 'FFFFFFFF'
local _dumpstart = 0x38*2 + 1
---
--- Handles errors
local function error(err)
print(ansicolors.red.."ERROR:"..ansicolors.reset, err)
core.clearCommandBuffer()
return nil, err
end
---
-- sets the global password variable
local function setPassword(password)
if password == nil or #password == 0 then
_password = nil;
elseif #password ~= 8 then
return false, 'Password must be 4 hex bytes'
else
_password = password
end
return true, 'Sets'
end
--- Parses response data
local function parseResponse(rawResponse)
local resp = Command.parse(rawResponse)
local len = tonumber(resp.arg1) * 2
return string.sub(tostring(resp.data), 0, len);
end
---
--- Sends raw data to PM3 and returns raw response if any
local function sendRaw(rawdata, options)
local flags = lib14a.ISO14A_COMMAND.ISO14A_RAW
if options.keep_signal then
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT
end
if options.connect then
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_CONNECT
end
if options.no_select then
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_SELECT
end
if options.append_crc then
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC
end
local arg2 = #rawdata / 2
if options.bits7 then
arg2 = arg2 | tonumber(bit32.lshift(7, 16))
end
local command = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER,
arg1 = flags,
arg2 = arg2,
data = rawdata}
return command:sendMIX(options.ignore_response)
end
---
--- Sends raw data to PM3 and returns parsed response
local function sendWithResponse(payload, options)
local opts;
if options then
opts = options
else
opts = {ignore_response = false, keep_signal = true, append_crc = true}
end
local rawResp, err = sendRaw(payload, opts)
if err then return err end
return parseResponse(rawResp)
end
---
-- Authenticates if password is provided
local function authenticate(password)
if password then
local resp, err = sendWithResponse('1B'..password)
if err then return err end
-- looking for 2 bytes (4 symbols) of PACK and 2 bytes (4 symbols) of CRC
if not resp or #resp ~=8 then return false, 'It seems that password is wrong' end
return true
end
return true
end
--
-- selects tag and authenticates if password is provided
local function connect()
core.clearCommandBuffer()
local info, err = lib14a.read(true, true)
if err then
lib14a.disconnect()
return false, err
end
core.clearCommandBuffer()
return authenticate(_password)
end
--
-- reconnects and selects tag again
local function reconnect()
lib14a.disconnect()
utils.Sleep(1)
local info, err = connect()
if not info then return false, "Unable to select tag: "..err end
return true
end
--
-- checks tag version
local function checkTagVersion()
local resp, err = sendWithResponse('60');
if err or resp == nil then return false, err end
if string.find(resp, '0034210101000E03') ~= 1 then return false, 'Wrong tag version: '..string.sub(resp,1,-5) end
return true
end
--
-- sends magic wakeup command
local function magicWakeup()
io.write('Sending magic wakeup command...')
local resp, err = sendRaw('5000', {ignore_response = false, append_crc = true})
if err or resp == nil then return false, "Unable to send first magic wakeup command: "..err end
resp, err = sendRaw('40', {connect = true, no_select = true, ignore_response = false, keep_signal = true, append_crc = false, bits7 = true})
if err or resp == nil then return false, "Unable to send first magic wakeup command: "..err end
resp, err = sendRaw('43', {ignore_response = false, keep_signal = true, append_crc = false})
if err or resp == nil then return false, "Unable to send second magic wakeup command: "..err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
return true
end
--
-- Writes dump to tag
local function writeDump(filename)
print(string.rep('--',20))
local info, err = connect()
if not info then return false, "Unable to select tag: "..err end
info, err = checkTagVersion()
if not info then return info, err end
-- load dump from file
if not filename then return false, 'No dump filename provided' end
io.write('Loading dump from file '..filename..'...')
local dump
dump, err = utils.ReadDumpFile(filename)
if not dump then return false, err end
if #dump ~= _dumpstart - 1 + 0xa4*2 then return false, 'Invalid dump file' end
print(ansicolors.green..'done'..ansicolors.reset..'.')
local resp
for i = 3, 0x23 do
local blockStart = i * 8 + _dumpstart
local block = string.sub(dump, blockStart, blockStart + 7)
local cblock = string.format('%02x',i)
io.write('Writing block 0x'..cblock..'...')
resp, err = sendWithResponse('A2'..cblock..block)
if err ~= nil then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
end
-- set password
io.write('Setting password and pack ')
info, err = reconnect()
if not info then return false, err end
local passwordStart = 0x27*8 + _dumpstart
local password = string.sub(dump, passwordStart, passwordStart + 7)
local packBlock = string.sub(dump, passwordStart+8, passwordStart + 15)
io.write('(password: '..password..') (pack block: '..packBlock..')...')
resp, err = sendWithResponse('A227'..password)
if err ~= nil then return false, err end
resp, err = sendWithResponse('A228'..packBlock)
if err ~= nil then return false, err end
if not setPassword(password) then return false, 'Unable to set password' end
info, err = reconnect()
if not info then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
-- set configs and locks
for i = 0x24, 0x26 do
local blockStart = i * 8 + _dumpstart
local block = string.sub(dump, blockStart, blockStart + 7)
local cblock = string.format('%02x',i)
io.write('Writing block 0x'..cblock..'...')
resp, err = sendWithResponse('A2'..cblock..block)
if err ~= nil then return false, err end
info, err = reconnect()
if not info then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
end
info, err = magicWakeup()
if not info then return false, err end
-- set uid and locks
for i = 0x2, 0x0, -1 do
local blockStart = i * 8 + _dumpstart
local block = string.sub(dump, blockStart, blockStart + 7)
local cblock = string.format('%02x',i)
io.write('Writing block 0x'..cblock..'...')
resp, err = sendWithResponse('A2'..cblock..block, {connect = i == 0x2, ignore_response = false, keep_signal = i ~= 0, append_crc = true})
if err ~= nil then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
end
print(ansicolors.green..'The dump has been written to the tag.'..ansicolors.reset)
return true
end
--
-- Wipes tag
local function wipe()
print(string.rep('--',20))
print('Wiping tag')
local info, err = connect()
if not info then return false, "Unable to select tag: "..err end
info, err = checkTagVersion()
if not info then return info, err end
local resp
-- clear lock bytes on page 0x02
resp, err = sendWithResponse('3000')
if err or resp == nil then return false, err end
local currentLowLockPage = string.sub(resp,17,24)
if(string.sub(currentLowLockPage,5,8) ~= '0000') then
info, err = magicWakeup()
if not info then return false, err end
local newLowLockPage = string.sub(currentLowLockPage,1,4)..'0000'
io.write('Clearing lock bytes on page 0x02...')
resp, err = sendWithResponse('A202'..newLowLockPage, {connect = true, ignore_response = false, keep_signal = true, append_crc = true})
if err ~= nil then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
end
-- clear lock bytes on page 0x24
io.write('Clearing lock bytes on page 0x24...')
info, err = reconnect()
if not info then return false, err end
resp, err = sendWithResponse('A224000000BD')
if err ~= nil then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
-- clear configs
io.write('Clearing cfg0 and cfg1...')
resp, err = sendWithResponse('A225000000FF')
if err ~= nil then return false, err end
resp, err = sendWithResponse('A22600050000')
if err ~= nil then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
-- clear password
io.write('Reseting password (and pack) to default ('.._defaultPassword..') and 0000...')
info, err = reconnect()
if not info then return false, err end
resp, err = sendWithResponse('A227'.._defaultPassword)
if err ~= nil then return false, err end
resp, err = sendWithResponse('A22800000000')
if err ~= nil then return false, err end
if not setPassword(_defaultPassword) then return false, 'Unable to set password' end
info, err = reconnect()
if not info then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
-- clear other blocks
for i = 3, 0x23 do
local cblock = string.format('%02x',i)
io.write('Clearing block 0x'..cblock..'...')
resp, err = sendWithResponse('A2'..cblock..'00000000')
if err ~= nil then return false, err end
print(ansicolors.green..'done'..ansicolors.reset..'.')
end
print(ansicolors.green..'The tag has been wiped.'..ansicolors.reset)
lib14a.disconnect()
return true
end
--
-- Prints help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- The main entry point
local function main(args)
if #args == 0 then return help() end
local dumpFilename = nil
for opt, value in getopt.getopt(args, 'hf:k:rw') do
local res, err
res = true
if opt == "h" then return help() end
if opt == "f" then dumpFilename = value end
if opt == 'k' then res, err = setPassword(value) end
if opt == 'r' then res, err = writeDump(dumpFilename) end
if opt == 'w' then res, err = wipe() end
if not res then return error(err) end
end
end
main(args)

View file

@ -90,13 +90,14 @@ def lprint(s='', end='\n', flush=False, prompt="[" + color("=", fg="yellow") +
- logfile (R)
"""
s = f"{prompt}" + f"\n{prompt}".join(s.split('\n'))
print(s, end=end, flush=flush)
safe_s = s.encode('utf-8', errors='ignore').decode('utf-8')
print(safe_s, end=end, flush=flush)
if log is True:
global logbuffer
if logfile is not None:
with open(logfile, 'a', encoding='utf-8') as f:
f.write(s + end)
f.write(safe_s + end)
else:
# buffering
logbuffer += s + end

View file

@ -600,7 +600,7 @@ static command_t CommandTable[] = {
{"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"},
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
{"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service }"},
{"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service... }"},
#ifdef HAVE_GD
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
#endif

View file

@ -914,7 +914,7 @@ int CmdHF14ASim(const char *Cmd) {
bool keypress = kbd_enter_pressed();
while (keypress == false) {
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0)
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false)
continue;
if (resp.status != PM3_SUCCESS)
@ -1403,10 +1403,10 @@ static int CmdHF14AAPDU(const char *Cmd) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool extendedAPDU = arg_get_lit(ctx, 6);
int le = arg_get_int_def(ctx, 7, 0);
uint8_t data[PM3_CMD_DATA_SIZE];
int datalen = 0;
@ -4037,7 +4037,7 @@ int CmdHF14AAIDSim(const char *Cmd) {
bool keypress = kbd_enter_pressed();
while (keypress == false) {
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) {
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) {
continue;
}

View file

@ -3029,7 +3029,9 @@ int infoHF14B(bool verbose, bool do_aid_search) {
// try unknown 14b read commands (to be identified later)
// could be read of calypso, CEPAS, moneo, or pico pass.
if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found");
if (verbose) {
PrintAndLogEx(FAILED, "no 14443-B tag found");
}
return PM3_EOPABORTED;
}

View file

@ -584,14 +584,14 @@ static void fuse_config(const picopass_hdr_t *hdr) {
uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]);
PrintAndLogEx(INFO, " Raw... " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8));
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit);
PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses);
PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8));
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit);
PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas);
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses);
uint8_t fuses = hdr->conf.fuses;
@ -1467,8 +1467,9 @@ static void iclass_decode_credentials(uint8_t *data) {
bool has_values = (memcmp(b7, empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(b7, zeros, PICOPASS_BLOCK_SIZE) != 0);
if (has_values && encryption == None) {
// todo: remove preamble/sentinel
PrintAndLogEx(INFO, "------------------------ " _CYAN_("Block 7 decoder") " --------------------------");
// todo: remove preamble/sentinel
if (has_new_pacs) {
iclass_decode_credentials_new_pacs(b7);
} else {
@ -1487,9 +1488,6 @@ static void iclass_decode_credentials(uint8_t *data) {
PrintAndLogEx(NORMAL, "");
decode_wiegand(top, mid, bot, 0);
}
} else {
PrintAndLogEx(INFO, "No unencrypted legacy credential found");
}
}
@ -1903,15 +1901,32 @@ static int CmdHFiClassDump(const char *Cmd) {
int key_len = 0;
uint8_t key[8] = {0};
bool auth = false;
CLIGetHexWithReturn(ctx, 2, key, &key_len);
int deb_key_nr = arg_get_int_def(ctx, 3, -1);
int credit_key_len = 0;
uint8_t credit_key[8] = {0};
CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len);
int credit_key_nr = arg_get_int_def(ctx, 5, -1);
bool elite = arg_get_lit(ctx, 6);
bool rawkey = arg_get_lit(ctx, 7);
bool use_replay = arg_get_lit(ctx, 8);
bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9);
bool force = arg_get_lit(ctx, 10);
bool shallow_mod = arg_get_lit(ctx, 11);
bool nosave = arg_get_lit(ctx, 12);
CLIParserFree(ctx);
bool auth = false;
bool have_credit_key = false;
// Sanity checks
if (key_len > 0 && deb_key_nr >= 0) {
PrintAndLogEx(ERR, "Please specify debit key or index, not both");
CLIParserFree(ctx);
return PM3_EINVARG;
}
@ -1919,7 +1934,6 @@ static int CmdHFiClassDump(const char *Cmd) {
auth = true;
if (key_len != 8) {
PrintAndLogEx(ERR, "Debit key is incorrect length");
CLIParserFree(ctx);
return PM3_EINVARG;
}
}
@ -1931,22 +1945,12 @@ static int CmdHFiClassDump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Using AA1 (debit) key[%d] " _GREEN_("%s"), deb_key_nr, sprint_hex(iClass_Key_Table[deb_key_nr], 8));
} else {
PrintAndLogEx(ERR, "Key number is invalid");
CLIParserFree(ctx);
return PM3_EINVARG;
}
}
int credit_key_len = 0;
uint8_t credit_key[8] = {0};
bool have_credit_key = false;
CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len);
int credit_key_nr = arg_get_int_def(ctx, 5, -1);
if (credit_key_len > 0 && credit_key_nr >= 0) {
PrintAndLogEx(ERR, "Please specify credit key or index, not both");
CLIParserFree(ctx);
return PM3_EINVARG;
}
@ -1955,7 +1959,6 @@ static int CmdHFiClassDump(const char *Cmd) {
have_credit_key = true;
if (credit_key_len != 8) {
PrintAndLogEx(ERR, "Credit key is incorrect length");
CLIParserFree(ctx);
return PM3_EINVARG;
}
}
@ -1968,21 +1971,10 @@ static int CmdHFiClassDump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Using AA2 (credit) key[%d] " _GREEN_("%s"), credit_key_nr, sprint_hex(iClass_Key_Table[credit_key_nr], 8));
} else {
PrintAndLogEx(ERR, "Key number is invalid");
CLIParserFree(ctx);
return PM3_EINVARG;
}
}
bool elite = arg_get_lit(ctx, 6);
bool rawkey = arg_get_lit(ctx, 7);
bool use_replay = arg_get_lit(ctx, 8);
bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9);
bool force = arg_get_lit(ctx, 10);
bool shallow_mod = arg_get_lit(ctx, 11);
bool nosave = arg_get_lit(ctx, 12);
CLIParserFree(ctx);
if ((use_replay + rawkey + elite) > 1) {
PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
return PM3_EINVARG;
@ -2005,7 +1997,6 @@ static int CmdHFiClassDump(const char *Cmd) {
clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t));
if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "command execution time out");
DropField();
@ -2062,9 +2053,11 @@ static int CmdHFiClassDump(const char *Cmd) {
PrintAndLogEx(INFO, "No keys needed, ignoring user supplied key");
}
} else {
if (auth == false) {
PrintAndLogEx(FAILED, "Run command with keys");
return PM3_ESOFT;
auth = true;
memcpy(key, iClass_Key_Table[0], 8);
PrintAndLogEx(SUCCESS, "Default to AA1 (debit) " _GREEN_("%s"), sprint_hex(key, sizeof(key)));
}
if (app_limit2 != 0) {
@ -2134,7 +2127,7 @@ static int CmdHFiClassDump(const char *Cmd) {
uint8_t tempbuf[0x100 * 8];
// response ok - now get bigbuf content of the dump
if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) {
if (GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
@ -2199,7 +2192,7 @@ static int CmdHFiClassDump(const char *Cmd) {
}
// get dumped data from bigbuf
if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) {
if (GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "command execution time out");
goto write_dump;
}
@ -2272,7 +2265,7 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata
SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) {
if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == false) {
if (verbose) PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
@ -2406,14 +2399,13 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) {
"Credit the epurse on an iCLASS tag. The provided key must be the credit key.\n"
"The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF.\n"
"The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.",
"hf iclass creditepurse -d FEFFFFFF -k 001122334455667B\n"
"hf iclass creditepurse -d FEFFFFFF --ki 0");
"hf iclass creditepurse --ki 0 -d FEFFFEFF");
void *argtable[] = {
arg_param_begin,
arg_str0("k", "key", "<hex>", "Credit key as 8 hex bytes"),
arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
arg_str1("d", "data", "<hex>", "data to write as 8 hex bytes"),
arg_str1("d", "data", "<hex>", "data to write as 4 hex bytes"),
arg_lit0(NULL, "elite", "elite computations applied to key"),
arg_lit0(NULL, "raw", "no computations applied to key"),
arg_lit0("v", "verbose", "verbose output"),
@ -2498,7 +2490,7 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) {
PacketResponseNG resp;
int isok;
if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == 0) {
if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == false) {
if (verbose) PrintAndLogEx(WARNING, "command execution time out");
isok = PM3_ETIMEOUT;
} else if (resp.status != PM3_SUCCESS) {
@ -2680,7 +2672,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size);
if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) {
if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "command execution time out");
DropField();
free(payload);
@ -2917,12 +2909,60 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
return PM3_SUCCESS;
}
static void iclass_cmp_print(uint8_t *b1, uint8_t *b2, const char *header1, const char *header2) {
char line1[240] = {0};
char line2[240] = {0};
strcat(line1, header1);
strcat(line2, header2);
for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++) {
int l1 = strlen(line1);
int l2 = strlen(line2);
uint8_t hi1 = NIBBLE_HIGH(b1[i]);
uint8_t low1 = NIBBLE_LOW(b1[i]);
uint8_t hi2 = NIBBLE_HIGH(b2[i]);
uint8_t low2 = NIBBLE_LOW(b2[i]);
if (hi1 != hi2) {
snprintf(line1 + l1, sizeof(line1) - l1, _RED_("%1X"), hi1);
snprintf(line2 + l2, sizeof(line2) - l2, _GREEN_("%1X"), hi2);
} else {
snprintf(line1 + l1, sizeof(line1) - l1, "%1X", hi1);
snprintf(line2 + l2, sizeof(line2) - l2, "%1X", hi2);
}
l1 = strlen(line1);
l2 = strlen(line2);
if (low1 != low2) {
snprintf(line1 + l1, sizeof(line1) - l1, _RED_("%1X"), low1);
snprintf(line2 + l2, sizeof(line2) - l2, _GREEN_("%1X"), low2);
} else {
snprintf(line1 + l1, sizeof(line1) - l1, "%1X", low1);
snprintf(line2 + l2, sizeof(line2) - l2, "%1X", low2);
}
}
PrintAndLogEx(INFO, "%s", line1);
PrintAndLogEx(INFO, "%s", line2);
}
static int CmdHFiClass_TearBlock(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass trbl",
"Tear off an iCLASS tag block",
"hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --tdb 100 --tde 150\n"
"hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150");
CLIParserInit(&ctx, "hf iclass tear",
"Tear off an iCLASS tag block\n"
"e-purse usually 300-500us to trigger the erase phase\n"
"also seen 1800-2100us on some cards\n",
"hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B -s 300 -e 600\n"
"hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 -s 300 -e 600\n"
"hf iclass tear --blk 2 -d fdffffffffffffff --ki 1 --credit -s 400 -e 500"
);
void *argtable[] = {
arg_param_begin,
@ -2937,83 +2977,30 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
arg_lit0(NULL, "nr", "replay of NR/MAC"),
arg_lit0("v", "verbose", "verbose output"),
arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
arg_int1(NULL, "tdb", "<dec>", "tearoff delay start in ms"),
arg_int1(NULL, "tde", "<dec>", "tearoff delay end in ms"),
arg_int1("s", NULL, "<dec>", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us"),
arg_int0("i", NULL, "<dec>", "tearoff delay increment (in us) - default 10"),
arg_int0("e", NULL, "<dec>", "tearoff delay end (in us) must be a higher value than the start delay"),
arg_int0(NULL, "loop", "<dec>", "number of times to loop per tearoff time"),
arg_int0(NULL, "sleep", "<ms>", "Sleep between each tear"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int key_len = 0;
uint8_t key[8] = {0};
CLIGetHexWithReturn(ctx, 1, key, &key_len);
int key_nr = arg_get_int_def(ctx, 2, -1);
if (key_len > 0 && key_nr >= 0) {
PrintAndLogEx(ERR, "Please specify key or index, not both");
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool auth = false;
if (key_len > 0) {
auth = true;
if (key_len != 8) {
PrintAndLogEx(ERR, "Key is incorrect length");
CLIParserFree(ctx);
return PM3_EINVARG;
}
} else if (key_nr >= 0) {
if (key_nr < ICLASS_KEYS_MAX) {
auth = true;
memcpy(key, iClass_Key_Table[key_nr], 8);
PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8));
} else {
PrintAndLogEx(ERR, "Key number is invalid");
CLIParserFree(ctx);
return PM3_EINVARG;
}
}
int blockno = arg_get_int_def(ctx, 3, 0);
int data_len = 0;
uint8_t data[8] = {0};
CLIGetHexWithReturn(ctx, 4, data, &data_len);
if (data_len != 8) {
PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 hex symbols)");
CLIParserFree(ctx);
return PM3_EINVARG;
}
int mac_len = 0;
uint8_t mac[4] = {0};
CLIGetHexWithReturn(ctx, 5, mac, &mac_len);
if (mac_len) {
if (mac_len != 4) {
PrintAndLogEx(ERR, "MAC must be 4 hex bytes (8 hex symbols)");
CLIParserFree(ctx);
return PM3_EINVARG;
}
}
int tearoff_start = arg_get_int_def(ctx, 12, 100);
int tearoff_end = arg_get_int_def(ctx, 13, 200);
if (tearoff_end <= tearoff_start) {
PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay.");
return PM3_EINVARG;
}
if (tearoff_start < 0 || tearoff_end <= 0) {
PrintAndLogEx(ERR, "Tearoff start/end delays should be bigger than 0.");
return PM3_EINVARG;
}
bool use_credit_key = arg_get_lit(ctx, 6);
bool elite = arg_get_lit(ctx, 7);
bool rawkey = arg_get_lit(ctx, 8);
@ -3021,58 +3008,231 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
bool verbose = arg_get_lit(ctx, 10);
bool shallow_mod = arg_get_lit(ctx, 11);
int tearoff_start = arg_get_int_def(ctx, 12, 100);
int tearoff_original_start = tearoff_start; // save original start value for later use
int tearoff_increment = arg_get_int_def(ctx, 13, 10);
int tearoff_end = arg_get_int_def(ctx, 14, tearoff_start + tearoff_increment + 500);
int tearoff_loop = arg_get_int_def(ctx, 15, 1);
int tearoff_sleep = arg_get_int_def(ctx, 16, 0);
CLIParserFree(ctx);
if ((use_replay + rawkey + elite) > 1) {
PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
// Sanity checks
if (key_len > 0 && key_nr >= 0) {
PrintAndLogEx(ERR, "Please specify key or index, not both");
return PM3_EINVARG;
}
bool auth = false;
if (key_len > 0) {
auth = true;
if (key_len != 8) {
PrintAndLogEx(ERR, "Key is incorrect length");
return PM3_EINVARG;
}
PrintAndLogEx(NORMAL, "");
}
if (key_nr >= 0) {
if (key_nr < ICLASS_KEYS_MAX) {
auth = true;
memcpy(key, iClass_Key_Table[key_nr], 8);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex_inrow(iClass_Key_Table[key_nr], 8));
} else {
PrintAndLogEx(ERR, "Key number is invalid");
return PM3_EINVARG;
}
}
if (data_len != 8) {
PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 hex symbols), got " _RED_("%u"), data_len);
return PM3_EINVARG;
}
if (mac_len && mac_len != 4) {
PrintAndLogEx(ERR, "MAC must be 4 hex bytes (8 hex symbols)");
return PM3_EINVARG;
}
if (tearoff_end <= tearoff_start) {
PrintAndLogEx(ERR, "Tearoff end delay must be larger than the start delay");
return PM3_EINVARG;
}
if (tearoff_start <= 0) {
PrintAndLogEx(ERR, "Tearoff_start delays must be larger than 0");
return PM3_EINVARG;
}
if (tearoff_end <= 0) {
PrintAndLogEx(ERR, "Tearoff_end delays must be larger than 0");
return PM3_EINVARG;
}
if ((use_replay + rawkey + elite) > 1) {
PrintAndLogEx(ERR, "Can not use a combo of `--elite`, `--raw`, `--nr`");
return PM3_EINVARG;
}
int loop_count = 0;
int isok = 0;
tearoff_params_t params;
bool read_ok = false;
while (tearoff_start < tearoff_end && !read_ok) {
//perform read here, repeat if failed or 00s
uint8_t keyType = 0x88; // debit key
uint8_t data_read_orig[8] = {0};
bool first_read = false;
bool reread = false;
while (!first_read) {
int res_orig = iclass_read_block_ex(key, blockno, 0x88, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read_orig, false);
if (res_orig == PM3_SUCCESS && !reread) {
if (memcmp(data_read_orig, zeros, 8) == 0) {
reread = true;
} else {
first_read = true;
reread = false;
}
} else if (res_orig == PM3_SUCCESS && reread) {
first_read = true;
reread = false;
}
if (use_credit_key) {
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key");
keyType = 0x18; // credit key
}
if (auth == false) {
PrintAndLogEx(SUCCESS, "No key supplied. Trying no authentication read/writes");
}
if (tearoff_loop > 1) {
PrintAndLogEx(SUCCESS, _YELLOW_("%u") " attempts / tearoff", tearoff_loop);
}
if (tearoff_sleep) {
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("%u") " ms delay between attempts", tearoff_sleep);
}
//check if the card is in secure mode or not
iclass_card_select_t payload_rdr = {
.flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
};
if (shallow_mod) {
payload_rdr.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
}
clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t));
if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "command execution time out");
DropField();
return PM3_ESOFT;
}
DropField();
if (resp.status == PM3_ERFTRANS) {
PrintAndLogEx(FAILED, "no tag found");
DropField();
return PM3_ESOFT;
}
iclass_card_select_resp_t *r = (iclass_card_select_resp_t *)resp.data.asBytes;
if (r->status == FLAG_ICLASS_NULL) {
PrintAndLogEx(FAILED, "failed to read block 0,1,2");
return PM3_ESOFT;
}
picopass_hdr_t *hdr = &r->header.hdr;
uint8_t pagemap = get_pagemap(hdr);
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
PrintAndLogEx(INFO, "Card in non-secure page mode detected");
auth = false;
}
if (pagemap == 0x0) {
PrintAndLogEx(WARNING, _RED_("No auth possible. Read only if RA is enabled"));
goto out;
}
bool read_auth = auth;
// perform initial read here, repeat if failed or 00s
uint8_t data_read_orig[8] = {0};
uint8_t ff_data[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
bool first_read = false;
bool reread = false;
bool erase_phase = false;
int res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read_orig, false);
if (res_orig == PM3_SUCCESS && !reread) {
if (memcmp(data_read_orig, zeros, 8) == 0) {
reread = true;
} else {
first_read = true;
reread = false;
}
} else if (res_orig == PM3_SUCCESS && reread) {
first_read = true;
reread = false;
}
PrintAndLogEx(SUCCESS, "Original block data... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig)));
PrintAndLogEx(SUCCESS, "New data to write..... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data)));
PrintAndLogEx(SUCCESS, "Target block.......... " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno);
// turn off Device side debug messages
uint8_t dbg_curr = DBG_NONE;
if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) {
return PM3_EFAILED;
}
if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS) {
return PM3_EFAILED;
}
// clear trace log
SendCommandNG(CMD_BUFF_CLEAR, NULL, 0);
PrintAndLogEx(INFO, "---------------------------------------");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n");
// Main loop
while ((tearoff_start <= tearoff_end) && (read_ok == false)) {
if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\naborted via keyboard.");
isok = PM3_EOPABORTED;
goto out;
}
params.on = true;
params.delay_us = tearoff_start;
handle_tearoff(&params, false);
PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")" ms", tearoff_start);
isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod);
switch (isok) {
case PM3_SUCCESS:
PrintAndLogEx(SUCCESS, "Wrote block " _YELLOW_("%d") " / " _YELLOW_("0x%02X") " ( " _GREEN_("ok") " )", blockno, blockno);
break;
case PM3_ETEAROFF:
break;
default:
PrintAndLogEx(FAILED, "Writing failed");
break;
// set tear off trigger
clearCommandBuffer();
tearoff_params_t params = {
.delay_us = (tearoff_start & 0xFFFF),
.on = true,
.off = false
};
int res = handle_tearoff(&params, verbose);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed to configure tear off");
isok = PM3_ESOFT;
goto out;
}
//read the data back
PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%u")" / "_YELLOW_("%d")" loops", params.delay_us, (tearoff_end & 0xFFFF), loop_count+1, tearoff_loop);
// write block - don't check the return value. As a tear-off occurred, the write failed.
iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod);
// read the data back
uint8_t data_read[8] = {0};
first_read = false;
reread = false;
bool decrease = false;
while (!first_read) {
int res = iclass_read_block_ex(key, blockno, 0x88, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false);
while (first_read == false) {
if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\naborted via keyboard.");
isok = PM3_EOPABORTED;
goto out;
}
if (blockno == 1) {
read_auth = false;
}
res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read, false);
if (res == PM3_SUCCESS && !reread) {
if (memcmp(data_read, zeros, 8) == 0) {
reread = true;
@ -3087,26 +3247,103 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
decrease = true;
}
}
if (decrease && tearoff_start > 0) { //if there was an error reading repeat the tearoff with the same delay
tearoff_start--;
// if there was an error reading repeat the tearoff with the same delay
if (decrease && (tearoff_start > tearoff_increment) && (tearoff_start >= tearoff_original_start)) {
tearoff_start -= tearoff_increment;
}
bool tear_success = true;
for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) {
if (data[i] != data_read[i]) {
tear_success = false;
bool expected_values = true;
if (memcmp(data_read, data, 8) != 0) {
tear_success = false;
}
if ((tear_success == false) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) {
// tearoff succeeded (partially)
expected_values = false;
if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) {
erase_phase = true;
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _CYAN_("Erase phase hit... ALL ONES"));
iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: ");
} else {
if (erase_phase) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write phase (post erase)"));
iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: ");
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _CYAN_("Tearing! unknown phase"));
iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: ");
}
}
if (blockno == 1) {
if (data_read[0] != data_read_orig[0]) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Application limit changed, from %u to %u", data_read_orig[0], data_read[0]);
isok = PM3_SUCCESS;
goto out;
}
if (data_read[7] != data_read_orig[7]) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Fuse changed, from %02x to %02x", data_read_orig[7], data_read[7]);
isok = PM3_SUCCESS;
goto out;
}
}
}
if (tear_success) { //tearoff succeeded
if (tear_success) { // tearoff succeeded with expected values
read_ok = true;
PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success!"));
PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read)));
} else { //tearoff did not succeed
PrintAndLogEx(FAILED, _RED_("Tear-off Failed!"));
tearoff_start++;
tear_success = true;
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Read: " _GREEN_("%s") " %s"
, sprint_hex_inrow(data_read, sizeof(data_read)),
(expected_values) ? _GREEN_(" -> Expected values!") : ""
);
}
loop_count++;
if (loop_count == tearoff_loop) {
tearoff_start += tearoff_increment;
loop_count = 0;
}
if (tearoff_sleep) {
msleep(tearoff_sleep);
}
PrintAndLogEx(INFO, "---------------");
}
out:
DropField();
if (setDeviceDebugLevel(verbose ? MAX(dbg_curr, DBG_INFO) : DBG_NONE, false) != PM3_SUCCESS) {
return PM3_EFAILED;
}
// disable tearoff in case of keyboard abort, or it'll trigger on next operation
clearCommandBuffer();
tearoff_params_t params = {
.delay_us = tearoff_start,
.on = false,
.off = true
};
handle_tearoff(&params, false);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Done!");
PrintAndLogEx(NORMAL, "");
clearCommandBuffer();
return isok;
}
@ -3502,7 +3739,6 @@ static int CmdHFiClassView(const char *Cmd) {
}
if (verbose) {
PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, (uint16_t)(bytes_read >> 3), (uint16_t)(bytes_read >> 3));
PrintAndLogEx(INFO, "Printing blocks from: " _YELLOW_("%02d") " to: " _YELLOW_("%02d"), (startblock == 0) ? 6 : startblock, endblock);
}
@ -4255,7 +4491,7 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) {
uint8_t startingKey[PICOPASS_BLOCK_SIZE] = {0};
CLIGetHexWithReturn(ctx, 4, startingKey, &startingkey_len);
uint64_t index = arg_get_int_def(ctx, 6, 0); //has to be 64 as we're bruteforcing 40 bits
uint64_t index = arg_get_int_def(ctx, 5, 0); //has to be 64 as we're bruteforcing 40 bits
index = index * 1000000;
CLIParserFree(ctx);
@ -5530,7 +5766,7 @@ static command_t CommandTable[] = {
{"view", CmdHFiClassView, AlwaysAvailable, "Display content from tag dump file"},
{"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "Write Picopass / iCLASS block"},
{"creditepurse", CmdHFiClassCreditEpurse, IfPm3Iclass, "Credit epurse value"},
{"trbl", CmdHFiClass_TearBlock, IfPm3Iclass, "Performs tearoff attack on iClass block"},
{"tear", CmdHFiClass_TearBlock, IfPm3Iclass, "Performs tearoff attack on iClass block"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("Recovery") " --------------------"},
// {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "Automatic key recovery tool for iCLASS"},
{"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "Check keys"},
@ -5634,7 +5870,7 @@ int info_iclass(bool shallow_mod) {
} else {
if ((r->status & FLAG_ICLASS_CC) == FLAG_ICLASS_CC) {
PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
PrintAndLogEx(SUCCESS, "E-purse: %s card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
}
if (memcmp(hdr->key_d, zeros, sizeof(zeros))) {
@ -5733,5 +5969,6 @@ int info_iclass(bool shallow_mod) {
}
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}

View file

@ -131,7 +131,7 @@ static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16
SendCommandMIX(CMD_HF_ISO14443A_READER, arg0, arg1, 0, cmd, len);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
return PM3_ETIMEOUT;
}

View file

@ -1915,9 +1915,13 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) {
continue;
}
if (resp.status != PM3_SUCCESS) continue;
if (resp.status != PM3_SUCCESS) {
continue;
}
uint8_t *data = resp.data.asBytes;
key64 = bytes_to_num(data + 10, 6);
@ -4005,9 +4009,13 @@ static int CmdHF14AMfChk(const char *Cmd) {
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) {
continue;
}
if (resp.status != PM3_SUCCESS) continue;
if (resp.status != PM3_SUCCESS) {
continue;
}
uint8_t *data = resp.data.asBytes;
key64 = bytes_to_num(data + 10, MIFARE_KEY_SIZE);
@ -4070,7 +4078,7 @@ out:
// Disable fast mode and send a dummy command to make it effective
g_conn.block_after_ACK = false;
SendCommandNG(CMD_PING, NULL, 0);
if (!WaitForResponseTimeout(CMD_PING, NULL, 1000)) {
if (WaitForResponseTimeout(CMD_PING, NULL, 1000) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
@ -6176,7 +6184,9 @@ static int CmdHF14AMfice(const char *Cmd) {
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, NULL, 0);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) goto out;
if (WaitForResponseTimeout(CMD_ACK, &resp, 3000) == false) {
goto out;
}
if (resp.oldarg[0]) goto out;
uint32_t items = resp.oldarg[2];

View file

@ -1684,7 +1684,7 @@ typedef struct {
} mfu_otp_identify_t;
static mfu_otp_identify_t mfu_otp_ident_table[] = {
{ "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, NULL },
{ "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, "report to iceman!" },
{ NULL, 0, 0, NULL, NULL, NULL }
};
@ -1963,7 +1963,7 @@ static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, const uint8_t *aut
// OTP checks
mfu_otp_identify_t *item = mfu_match_otp_fingerprint(uid, data);
if (item) {
PrintAndLogEx(SUCCESS, _GREEN_("%s"), item->desc);
PrintAndLogEx(SUCCESS, _BACK_GREEN_(" %s "), item->desc);
res = PM3_SUCCESS;
if (item->hint) {
@ -4628,7 +4628,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
// we be getting ACK that we are silently ignoring here..
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) {
if (WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT;
}
@ -4649,11 +4649,13 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
got_post = true;
}
}
if (! got_post) {
if (!got_post) {
PrintAndLogEx(FAILED, "Failed to read block BEFORE");
error_retries++;
continue; // try again
}
error_retries = 0;
char prestr[20] = {0};
snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
@ -4936,7 +4938,7 @@ static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) {
clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload));
if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) {
if (WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "\ntear off command failed");
continue;
}

View file

@ -562,7 +562,7 @@ static int select_DF_verify(uint8_t *response, uint8_t response_length, uint8_t
}
// ----------------- MAC Key Generation -----------------
uint8_t cmac[8];
uint8_t cmac[16];
uint8_t MAC_key[24] = {0x00};
memcpy(MAC_key, keys[key_index].privMacKey, 16);
create_cmac(MAC_key, input, cmac, sizeof(input), encryption_algorithm);
@ -1351,7 +1351,7 @@ static int CmdHfSeosGDF(const char *Cmd) {
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int key_index = arg_get_int_def(ctx, 1, -1);
int key_index = arg_get_int_def(ctx, 1, 0);
CLIParserFree(ctx);
return seos_global_df(key_index);

View file

@ -664,7 +664,7 @@ static int CmdHFTexkomReader(const char *Cmd) {
SendCommandNG(CMD_HF_ACQ_RAW_ADC, (uint8_t *)&samplesCount, sizeof(uint32_t));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500)) {
if (WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}

View file

@ -187,7 +187,7 @@ int CmdHfThinFilmSim(const char *Cmd) {
int ret;
while (!(ret = kbd_enter_pressed())) {
if (WaitForResponseTimeout(CMD_HF_THINFILM_SIMULATE, &resp, 500) == 0) {
if (WaitForResponseTimeout(CMD_HF_THINFILM_SIMULATE, &resp, 500) == false) {
continue;
}

View file

@ -928,15 +928,19 @@ static int CmdTune(const char *Cmd) {
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING, NULL, 0);
PacketResponseNG resp;
PrintAndLogEx(INPLACE, "% 3i", timeout_max - timeout);
while (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING, &resp, 500)) {
while (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING, &resp, 500) == false) {
fflush(stdout);
if (timeout >= timeout_max) {
PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting...");
return PM3_ETIMEOUT;
}
timeout++;
PrintAndLogEx(INPLACE, "% 3i", timeout_max - timeout);
}
PrintAndLogEx(NORMAL, "");
if (resp.status != PM3_SUCCESS) {
@ -1607,7 +1611,7 @@ void pm3_version_short(void) {
if (ptr != NULL) {
char *ptr_end = strstr(ptr, "\n");
if (ptr_end != NULL) {
uint8_t len = ptr_end - 19 - ptr;
uint8_t len = ptr_end - 12 - ptr;
PrintAndLogEx(NORMAL, " Bootrom... %.*s", len, ptr + 12);
}
}
@ -1617,7 +1621,7 @@ void pm3_version_short(void) {
if (ptr != NULL) {
char *ptr_end = strstr(ptr, "\n");
if (ptr_end != NULL) {
uint8_t len = ptr_end - 14 - ptr;
uint8_t len = ptr_end - 12 - ptr;
PrintAndLogEx(NORMAL, " OS........ %.*s", len, ptr + 12);
}
}

View file

@ -435,15 +435,17 @@ int CmdLFCommandRead(const char *Cmd) {
i = 10;
// 20sec wait loop
while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) {
while (WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) == false && i != 0) {
if (verbose) {
PrintAndLogEx(NORMAL, "." NOLF);
}
i--;
}
if (verbose) {
PrintAndLogEx(NORMAL, "");
}
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "command failed.");
return PM3_ESOFT;
@ -595,7 +597,7 @@ int lf_getconfig(sample_config *config) {
SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000)) {
if (WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
@ -797,10 +799,12 @@ static int lf_read_internal(bool realtime, bool verbose, uint64_t samples) {
payload.samples = (samples > MAX_LF_SAMPLES) ? MAX_LF_SAMPLES : samples;
SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (is_trigger_threshold_set) {
WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp);
} else {
if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) {
if (WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "(lf_read) command execution time out");
return PM3_ETIMEOUT;
}

View file

@ -2013,7 +2013,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
PrintAndLogEx(INFO, "----------------------------------------------------------------------------\n");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>'") " to exit");
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------------\n");

View file

@ -466,7 +466,7 @@ int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) {
ng.flags = 0;
SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng));
if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT)) {
if (WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT) == false) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
@ -664,7 +664,7 @@ int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t p
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng));
if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, 2000)) {
if (WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, 2000) == false) {
PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation.");
return PM3_ETIMEOUT;
}
@ -1992,7 +1992,7 @@ static int CmdT55xxDangerousRaw(const char *Cmd) {
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng));
if (!WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000)) {
if (WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000) == false) {
PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation.");
return PM3_ETIMEOUT;
}
@ -2840,7 +2840,7 @@ bool AcquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, u
clearCommandBuffer();
SendCommandNG(CMD_LF_T55XX_READBL, (uint8_t *)&payload, sizeof(payload));
if (!WaitForResponseTimeout(CMD_LF_T55XX_READBL, NULL, 2500)) {
if (WaitForResponseTimeout(CMD_LF_T55XX_READBL, NULL, 2500) == false) {
PrintAndLogEx(WARNING, "command execution time out");
return false;
}
@ -3435,7 +3435,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
PacketResponseNG resp;
uint8_t timeout = 0;
while (!WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000)) {
while (WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000) == false) {
timeout++;
PrintAndLogEx(NORMAL, "." NOLF);
if (timeout > 180) {

View file

@ -172,7 +172,7 @@ static int CmdVikingClone(const char *Cmd) {
SendCommandNG(CMD_LF_VIKING_CLONE, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_LF_VIKING_CLONE, &resp, T55XX_WRITE_TIMEOUT)) {
if (WaitForResponseTimeout(CMD_LF_VIKING_CLONE, &resp, T55XX_WRITE_TIMEOUT) == false) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}

View file

@ -663,7 +663,7 @@ static int CmdSmartUpgrade(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_SMART_UPLOAD, (uint8_t *)&upload, sizeof(upload));
if (!WaitForResponseTimeout(CMD_SMART_UPLOAD, &resp, 2000)) {
if (WaitForResponseTimeout(CMD_SMART_UPLOAD, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply");
free(firmware);
return PM3_ETIMEOUT;
@ -695,7 +695,7 @@ static int CmdSmartUpgrade(const char *Cmd) {
free(firmware);
SendCommandNG(CMD_SMART_UPGRADE, (uint8_t *)&payload, sizeof(payload));
if (!WaitForResponseTimeout(CMD_SMART_UPGRADE, &resp, 2500)) {
if (WaitForResponseTimeout(CMD_SMART_UPGRADE, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply");
return PM3_ETIMEOUT;
}
@ -876,7 +876,7 @@ static int CmdSmartSetClock(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_SMART_SETCLOCK, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500)) {
if (WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "smart card select failed");
return PM3_ETIMEOUT;
}

View file

@ -35,7 +35,7 @@ static int usart_tx(uint8_t *data, size_t len) {
clearCommandBuffer();
SendCommandNG(CMD_USART_TX, data, len);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_USART_TX, &resp, 1000)) {
if (WaitForResponseTimeout(CMD_USART_TX, &resp, 1000) == false) {
return PM3_ETIMEOUT;
}
return resp.status;
@ -49,7 +49,7 @@ static int usart_rx(uint8_t *data, size_t *len, uint32_t waittime) {
payload.waittime = waittime;
SendCommandNG(CMD_USART_RX, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_USART_RX, &resp, waittime + 500)) {
if (WaitForResponseTimeout(CMD_USART_RX, &resp, waittime + 500) == false) {
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
@ -99,7 +99,7 @@ static int set_usart_config(uint32_t baudrate, uint8_t parity) {
payload.parity = parity;
SendCommandNG(CMD_USART_CONFIG, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_USART_CONFIG, &resp, 1000)) {
if (WaitForResponseTimeout(CMD_USART_CONFIG, &resp, 1000) == false) {
return PM3_ETIMEOUT;
}
return resp.status;

View file

@ -871,7 +871,7 @@ int TestProxmark(pm3_device_t *dev) {
#endif
PacketResponseNG resp;
if (WaitForResponseTimeoutW(CMD_PING, &resp, timeout, false) == 0) {
if (WaitForResponseTimeoutW(CMD_PING, &resp, timeout, false) == false) {
return PM3_ETIMEOUT;
}
@ -881,7 +881,7 @@ int TestProxmark(pm3_device_t *dev) {
}
SendCommandNG(CMD_CAPABILITIES, NULL, 0);
if (WaitForResponseTimeoutW(CMD_CAPABILITIES, &resp, 1000, false) == 0) {
if (WaitForResponseTimeoutW(CMD_CAPABILITIES, &resp, 1000, false) == false) {
return PM3_ETIMEOUT;
}

View file

@ -165,6 +165,7 @@ static char *filenamemcopy(const char *preferredName, const char *suffix) {
char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t));
if (fileName == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
return NULL;
}
@ -993,8 +994,8 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata,
}
*pdata = calloc(fsize, sizeof(uint8_t));
if (!*pdata) {
PrintAndLogEx(FAILED, "error, cannot allocate memory");
if (*pdata == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
fclose(f);
return PM3_EMALLOC;
}
@ -1044,8 +1045,8 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
}
*pdata = calloc(fsize, sizeof(uint8_t));
if (!*pdata) {
PrintAndLogEx(FAILED, "error, cannot allocate memory");
if (*pdata == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
fclose(f);
return PM3_EMALLOC;
}
@ -1091,6 +1092,7 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
uint8_t *newdump = realloc(*pdata, counter);
if (newdump == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
free(*pdata);
return PM3_EMALLOC;
} else {
@ -1366,8 +1368,8 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) {
}
*pdata = calloc(fsize, sizeof(uint8_t));
if (!*pdata) {
PrintAndLogEx(FAILED, "error, cannot allocate memory");
if (*pdata == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
fclose(f);
return PM3_EMALLOC;
}
@ -1414,6 +1416,7 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) {
uint8_t *newdump = realloc(*pdata, counter);
if (newdump == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
free(*pdata);
return PM3_EMALLOC;
} else {
@ -2358,6 +2361,7 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo
// allocate some space for the dictionary
*pdata = calloc(block_size, sizeof(uint8_t));
if (*pdata == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
free(path);
return PM3_EFILE;
}
@ -2377,9 +2381,10 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo
if ((*keycnt * (keylen >> 1)) >= mem_size) {
mem_size += block_size;
*pdata = realloc(*pdata, mem_size);
*pdata = realloc(*pdata, mem_size);
if (*pdata == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
retval = PM3_EFILE;
fclose(f);
goto out;
@ -2473,7 +2478,7 @@ int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya
*keya = calloc(fsize, sizeof(uint8_t));
if (*keya == NULL) {
PrintAndLogEx(FAILED, "error, cannot allocate memory");
PrintAndLogEx(WARNING, "Failed to allocate memory");
fclose(f);
free(path);
return PM3_EMALLOC;
@ -2483,7 +2488,7 @@ int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya
*keyb = calloc(fsize, sizeof(uint8_t));
if (*keyb == NULL) {
PrintAndLogEx(FAILED, "error, cannot allocate memory");
PrintAndLogEx(WARNING, "Failed to allocate memory");
fclose(f);
free(*keya);
free(path);
@ -2663,6 +2668,7 @@ static int convert_plain_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose)
mfu_dump_t *mfu = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t));
if (mfu == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
@ -2700,6 +2706,7 @@ static int convert_old_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) {
mfu_dump_t *mfu_dump = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t));
if (mfu_dump == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
@ -2846,6 +2853,7 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
// explicit absolute (/) or relative path (./) => try only to match it directly
char *filename = calloc(strlen(searchname) + 1, sizeof(char));
if (filename == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
@ -3081,7 +3089,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
case JSON: {
*pdump = calloc(maxdumplen, sizeof(uint8_t));
if (*pdump == NULL) {
PrintAndLogEx(WARNING, "fail, cannot allocate memory");
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
@ -3121,7 +3129,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
*pdump = calloc(maxdumplen, sizeof(uint8_t));
if (*pdump == NULL) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
res = loadFileNFC_safe(fn, *pdump, maxdumplen, dumplen, dumptype);

View file

@ -281,7 +281,7 @@ const static vocabulary_t vocabulary[] = {
{ 1, "hf iclass view" },
{ 0, "hf iclass wrbl" },
{ 0, "hf iclass creditepurse" },
{ 0, "hf iclass trbl" },
{ 0, "hf iclass tear" },
{ 0, "hf iclass chk" },
{ 1, "hf iclass loclass" },
{ 1, "hf iclass lookup" },

View file

@ -303,7 +303,7 @@ static int l_GetFromFlashMemSpiffs(lua_State *L) {
// get size from spiffs itself !
SendCommandNG(CMD_SPIFFS_STAT, (uint8_t *)destfilename, 32);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000))
if (WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000) == false)
return returnToLuaWithError(L, "No response from the device");
len = resp.data.asDwords[0];

View file

@ -252,6 +252,10 @@ endif
# WITH_FPC_USART_* needs WITH_FPC_USART :
ifneq (,$(findstring WITH_FPC_USART_,$(PLATFORM_DEFS)))
PLATFORM_DEFS += -DWITH_FPC_USART
ifeq ($(USART_BAUD_RATE),)
USART_BAUD_RATE=115200
endif
PLATFORM_DEFS += -DUSART_BAUD_RATE=$(USART_BAUD_RATE)
endif
PLATFORM_DEFS_INFO = $(strip $(filter-out STANDALONE%, $(subst -DWITH_,,$(PLATFORM_DEFS))))

View file

@ -1342,7 +1342,6 @@
"-t, --timeout <ms> Timeout in milliseconds",
"-b <dec> Number of bits to send. Useful for send partial byte",
"-v, --verbose Verbose output",
"--mag Use Apple magsafe polling",
"--topaz Use Topaz protocol to send command",
"--crypto1 Use crypto1 session",
"<hex> Raw bytes to send"
@ -1354,8 +1353,7 @@
"description": "Act as a ISO-14443a reader to identify tag. Look for ISO-14443a tags until Enter or the pm3 button is pressed",
"notes": [
"hf 14a reader",
"hf 14a reader -@ -> Continuous mode",
"hf 14a reader --mag -> trigger apple magsafe polling"
"hf 14a reader -@ -> Continuous mode"
],
"offline": false,
"options": [
@ -1364,7 +1362,6 @@
"-s, --silent silent (no messages)",
"--drop just drop the signal field",
"--skip ISO14443-3 select only (skip RATS)",
"--mag Use Apple magsafe polling",
"-@ continuous reader mode",
"-w, --wait wait for card"
],
@ -3204,7 +3201,7 @@
},
"hf help": {
"command": "hf help",
"description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
"description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service... } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
"notes": [
"hf list --frame -> show frame delay times",
"hf list -1 -> use trace buffer"
@ -3288,15 +3285,14 @@
"command": "hf iclass creditepurse",
"description": "Credit the epurse on an iCLASS tag. The provided key must be the credit key. The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF. The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.",
"notes": [
"hf iclass creditepurse -d FEFFFFFF -k 001122334455667B",
"hf iclass creditepurse -d FEFFFFFF --ki 0"
"hf iclass creditepurse --ki 0 -d FEFFFEFF"
],
"offline": false,
"options": [
"-h, --help This help",
"-k, --key <hex> Credit key as 8 hex bytes",
"--ki <dec> Key index to select key from memory 'hf iclass managekeys'",
"-d, --data <hex> data to write as 8 hex bytes",
"-d, --data <hex> data to write as 4 hex bytes",
"--elite elite computations applied to key",
"--raw no computations applied to key",
"-v, --verbose verbose output",
@ -3720,12 +3716,13 @@
],
"usage": "hf iclass sniff [-hj]"
},
"hf iclass trbl": {
"command": "hf iclass trbl",
"description": "Tear off an iCLASS tag block",
"hf iclass tear": {
"command": "hf iclass tear",
"description": "Tear off an iCLASS tag block e-purse usually 300-500us to trigger the erase phase also seen 1800-2100us on some cards",
"notes": [
"hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --tdb 100 --tde 150",
"hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150"
"hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B -s 300 -e 600",
"hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 -s 300 -e 600",
"hf iclass tear --blk 2 -d fdffffffffffffff --ki 1 --credit -s 400 -e 500"
],
"offline": false,
"options": [
@ -3741,10 +3738,13 @@
"--nr replay of NR/MAC",
"-v, --verbose verbose output",
"--shallow use shallow (ASK) reader modulation instead of OOK",
"--tdb <dec> tearoff delay start in ms",
"--tde <dec> tearoff delay end in ms"
"-s <dec> tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us",
"-i <dec> tearoff delay increment (in us) - default 10",
"-e <dec> tearoff delay end (in us) must be a higher value than the start delay",
"--loop <dec> number of times to loop per tearoff time",
"--sleep <ms> Sleep between each tear"
],
"usage": "hf iclass trbl [-hv] [-k <hex>] [--ki <dec>] --blk <dec> -d <hex> [-m <hex>] [--credit] [--elite] [--raw] [--nr] [--shallow] --tdb <dec> --tde <dec>"
"usage": "hf iclass tear [-hv] [-k <hex>] [--ki <dec>] --blk <dec> -d <hex> [-m <hex>] [--credit] [--elite] [--raw] [--nr] [--shallow] -s <dec> [-i <dec>] [-e <dec>] [--loop <dec>] [--sleep <ms>]"
},
"hf iclass unhash": {
"command": "hf iclass unhash",
@ -13354,6 +13354,6 @@
"metadata": {
"commands_extracted": 767,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2025-04-20T09:18:59"
"extracted_on": "2025-05-25T12:38:36"
}
}

View file

@ -404,7 +404,7 @@ Check column "offline" for their availability.
|`hf iclass view `|Y |`Display content from tag dump file`
|`hf iclass wrbl `|N |`Write Picopass / iCLASS block`
|`hf iclass creditepurse `|N |`Credit epurse value`
|`hf iclass trbl `|N |`Performs tearoff attack on iClass block`
|`hf iclass tear `|N |`Performs tearoff attack on iClass block`
|`hf iclass chk `|N |`Check keys`
|`hf iclass loclass `|Y |`Use loclass to perform bruteforce reader attack`
|`hf iclass lookup `|Y |`Uses authentication trace to check for key in dictionary file`
@ -786,7 +786,7 @@ Check column "offline" for their availability.
### hf vas
{ Apple Value Added Service }
{ Apple Value Added Service... }
|command |offline |description
|------- |------- |-----------

View file

@ -73,9 +73,9 @@ There is a docker image with webpack installed which has been built which you ca
```
docker pull nhutton/prox-container:webp_image_complete
docker run -v <LOCAL_PATH>/proxmark3:/tmp --rm -it nhutton/prox-container:webp_image_complete bash
$ cd /tmp/proxmark/fpga
$ make all
docker run -v <LOCAL_PATH>/proxmark3:/tmp/proxmark3 --rm -it nhutton/prox-container:1.0 bash
$ cd /tmp/proxmark3/fpga
$ make all -j
```
In order to save space, these fpga images are LZ4 compressed and included in the fullimage.elf file when compiling the ARM SRC. `make armsrc`

View file

@ -2356,6 +2356,36 @@ After communication to iKey LLC (importer of those tags to Russian market), new
[+] ATS: 85 00 00 A0 00 00 0A 3C 00 04 03 01 01 00 0E 03 [ C8 1D ]
```
### Magic commands
^[Top](#top)
Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag or clear previously written tag.
Usage:
1. Restore dump to tag:
```
script run hf_mfu_ultra -f <dump filename> -k <passwd> -r
```
2. Wipe tag (use it to prepare tag for restoring another dump):
```
script run hf_mfu_ultra -k <passwd> -w
```
3. Show help:
```
script run hf_mfu_ultra -h
```
Examples:
1. Restore dump to tag:
```
script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r
```
2. Wipe tag:
```
script run hf_mfu_ultra -k 1d237f76 -w
```
## UL-5
^[Top](#top)
@ -2389,6 +2419,28 @@ The manufacturer confirmed unpersonalized tags could be identified by first 2 by
* `AA 55...`
### Magic commands
^[Top](#top)
Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag.
Usage:
1. Restore dump to tag:
```
script run hf_mfu_ultra -f <dump filename> -k <passwd> -r
```
3. Show help:
```
script run hf_mfu_ultra -h
```
Examples:
1. Restore dump to tag:
```
script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r
```
## UL, other chips
** TODO **

View file

@ -16,8 +16,9 @@
#ifndef __USART_DEFS_H
#define __USART_DEFS_H
//#define USART_BAUD_RATE 9600
#ifndef USART_BAUD_RATE
#define USART_BAUD_RATE 115200
#endif
// BT HC-06 physical layer runs at 128kbps
// so it's possible to gain a little bit by using 230400
// with some risk to overflow its internal buffers:

33
pm3
View file

@ -136,11 +136,15 @@ function get_pm3_list_Windows {
PM3LIST=()
# Normal SERIAL PORTS (COM)
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%' Or PNPDeviceID LIKE '%VID_2D2D&PID_504D%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
DEV=${DEV/ */}
for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.PNPDeviceID -like '*VID_9AC4&PID_4B8F*' -or \$_.PNPDeviceID -like '*VID_2D2D&PID_504D*'} | Select -expandproperty DeviceID" 2>/dev/null); do
_comport=$DEV
#prevent soft bricking when using pm3-flash-all on an outdated bootloader
if [ $(basename -- "$0") = "pm3-flash-all" ]; then
line=$(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}');
line=$($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null);
if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then
echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!"
exit 1
@ -154,8 +158,8 @@ function get_pm3_list_Windows {
#BT direct SERIAL PORTS (COM)
if $FINDBTRFCOMM; then
for DEV in $(wmic /locale:ms_409 path Win32_PnPEntity Where "Caption LIKE '%Bluetooth%(COM%'" Get Name 2> /dev/null | awk -b 'match($0,/(COM[0-9]+)/,m){print m[1]}'); do
DEV=${DEV/ */}
for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_PnPEntity | Where-Object Caption -like 'Standard Serial over Bluetooth link (COM*' | Select Name" 2>/dev/null); do
PM3LIST+=("$DEV")
if [ ${#PM3LIST[*]} -ge "$N" ]; then
return
@ -165,8 +169,8 @@ function get_pm3_list_Windows {
#white BT dongle SERIAL PORTS (COM)
if $FINDBTDONGLE; then
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_10C4&PID_EA60%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
DEV=${DEV/ */}
for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_10C4&PID_EA60*' | Select -expandproperty DeviceID" 2>/dev/null); do
PM3LIST+=("$DEV")
if [ ${#PM3LIST[*]} -ge "$N" ]; then
return
@ -497,6 +501,21 @@ if [ "$HOSTOS" = "LINUX" ]; then
elif [ "$HOSTOS" = "DARWIN" ]; then
GETPM3LIST=get_pm3_list_macOS
elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then
# First try finding it using the PATH environment variable
PSHEXE=$(command -v powershell.exe 2>/dev/null)
# If it fails (such as if WSLENV is not set), try using the default installation path
if [ -z "$PSHEXE" ]; then
PSHEXE=/cygdrive/c/WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe
fi
# Finally test if PowerShell is working
if ! "$PSHEXE" exit >/dev/null 2>&1; then
echo >&2 "[!!] Cannot run powershell.exe in your MINGW environment"
exit 1
fi
GETPM3LIST=get_pm3_list_Windows
else
echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS"