Issue origin:
Commit 6b7665ed5 "Added live fc/cn update to hf iclass tagsim" added a data_available() poll inside the per-byte DMA loop of GetIso15693CommandFromReader so the ARM could drop out of RF-listen and process live emulator updates.
Before that commit, that tight loop had no USB poll at all — only gotFrame / BUTTON_PRESS / WDT_HIT. Verified via git show 6b7665ed5^:armsrc/iso15693.c.
Why it shows up on sim -t 3/6/7: those are the FULL sim modes that share do_iclass_simulation. Between reader commands the decoder sits in STATE_READER_UNSYNCD, so the gated poll at iso15693.c:1570-1575 fires every byte (reading UDP peripheral registers). With DMA filling at ~1 byte / ~19 µs, the added USB register reads plus jitter occasionally push the CPU past the 90% lag threshold → behindBy 461 with DMA_BUFFER_SIZE=512.
Commit fb8f94fa2 narrowed the gate to UNSYNCD to stop mid-frame exits, but the per-byte poll itself is still what's new on that path.
Fix:
New mode constant in include/iclass_cmd.h:
#define ICLASS_SIM_MODE_FULL_LIVE 8 // FULL + allow USB interrupt for live emul updates
Treat it identically to ICLASS_SIM_MODE_FULL everywhere except for the poll gate.
Add a flag param to GetIso15693CommandFromReader — e.g. bool allow_usb_interrupt in iso15693.c:1495 and iso15693.h:42. Wrap the poll:
if (allow_usb_interrupt &&
(dr->state == STATE_READER_UNSYNCD ||
dr->state == STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF) &&
data_available()) { ... }
Pass true only for live mode in do_iclass_simulation iclass.c:502:
bool live = (simulationMode == ICLASS_SIM_MODE_FULL_LIVE);
len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time, live);
The len == -2 drain block stays but becomes dead code for non-live modes (never returns -2).
Client side: cmdhficlass.c:1687 (CmdHFiClassTagSim) sends ICLASS_SIM_MODE_FULL_LIVE. CmdHFiClassSim -t 3/6/7 keeps sending ICLASS_SIM_MODE_FULL / _GLITCH / _GLITCH_KEY.
Other callers (iso15693.c:2270, iclass.c:1121 = reader-attack sim) pass false.
Result:
hf iclass sim -t 3/6/7 → byte-inner loop is back to its pre-tagsim shape → no blow-buffer abort.
hf iclass tagsim → keeps live update ability; still has the overhead, but that's the trade-off the feature needs.
Add an interactive command for performing tear-off attacks on ST25TB/SRx
monotonic counter blocks. This exploits EEPROM tearing to increment
counters that normally can only be decremented, based on the
near-field-chaos project by SecLabz.
The command sweeps tear-off timing from --start downward in --adj
microsecond steps, automatically consolidates partial writes, verifies
stability across multiple reads, and reports progress in real-time with
color-coded output.
Performance optimizations:
- One-time full iso14443b_setup() at start; subsequent field cycles use
lightweight tearoff_field_on()/tearoff_field_off() that skip FPGA
bitstream reload and buffer reallocation
- Periodic CMD_WTX keepalives to prevent USB timeouts during long attacks
- Calls FpgaResetBitstream() on exit to ensure clean FPGA state
Usage: hf 14b tearoff -b <block> -d <target> [--start <us>] [--adj <us>]
Ubuntu Build and Test / ubuntu-make (push) Successful in 5m35s
Ubuntu Build and Test / ubuntu-make-btaddon (push) Successful in 5m11s
Ubuntu Build and Test / ubuntu-cmake (push) Failing after 4m33s
Windows Build and Test / proxspace (push) Has been cancelled
Windows Build and Test / wsl (push) Has been cancelled
MacOS Build and Test / macos-make (push) Has been cancelled
MacOS Build and Test / macos-make-btaddon (push) Has been cancelled
MacOS Build and Test / macos-cmake (push) Has been cancelled
CodeQL / Analyze (python) (push) Failing after 2m7s
CodeQL / Analyze (cpp) (push) Failing after 9m27s
Some static RAMFUNC got inlined which means they weren't relocated in RAM.
By forcing noinline on RAMFUNC, the following functions move to RAM:
F .data 00000034 optimizedSniff
F .data 00000148 skipSniff
F .data 000002c8 ManchesterDecoding_Thinfilm
But ManchesterDecoding_Thinfilm worked fine without being in RAM,
so we remove its RAMFUNC attribute and it works as previously,
and avoid eating some RAM bytes.
In summary, impacted command is only:
hf sniff