You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
lf t55xx dump and lf t55xx rdbl extract each 32-bit block at a bit offset cached from the last lf t55xx detect, and never re-derive it from the buffer actually being decoded. When a later read's demodulation starts on a different bit boundary than the detect-time capture did, the returned word is a bit rotation of the true block - silently, with no error. detect is unaffected because it searches for the offset in the same buffer it just demodulated.
client/src/cmdlft55xx.c (unchanged at master fb3ec70):
boolGetT55xxBlockData(uint32_t*blockdata) {
if (g_DemodBufferLen==0)
return false;
uint8_tidx=config.offset; // <-- cached by the LAST detect, on a DIFFERENT captureif (idx+32>g_DemodBufferLen) { ... return false; }
*blockdata=PackBits(0, 32, g_DemodBuffer+idx);
return true;
}
config.offset is only ever assigned in the detect path (config.offset = tests[i].offset;), where it is found by searching for a plausible configuration block.
Observed output - same tag, same placement, seconds apart. 001070C0 was written to block 0, detect reads it correctly, the first dump is correct then the second dump returns 0020E180, which is exactly rol1(001070C0):
[usb] pm3 --> lf t55xx write -b 0 -d 001070C0 --verify
[=] Writing page 0 block: 00 data: 0x001070C0
[!] ⚠️ Write could not validate the written data <-- the write actually SUCCEEDED
[usb] pm3 --> lf t55xx detect
[=] Modulation........ FSK2a
[=] Block0............ 001070C0 (auto detect) <-- detect is correct
[usb] pm3 --> lf t55xx dump
[+] 00 | 001070C0 | <-- correct
[+] 05 | B532CCCC | <-- rol1 of 5A996666
[usb] pm3 --> lf t55xx dump
[+] 00 | 0020E180 | <-- rol1 of 001070C0
[+] 05 | 5A996666 | <-- now correct
Three consequences, in increasing severity:
lf t55xx dump returns wrong data that looks valid - no checksum, no warning.
lf t55xx write --verifyreports successful writes as failures, because it validates by reading back through the same path (see the first line above). Users re-write, or conclude a tag is faulty.
lf t55xx restore of an affected dump writes the rotated data back permanently, so a tag can be made to hold a rotated copy of its own contents. This turns a read bug into data loss.
To Reproduce
Place a T5577 on the LF antenna.
Write a payload that is not byte-periodic - this matters, A5A5A5A5 lands on itself under many wrong rotations and hides the bug: lf t55xx write -b 1 -d 1D996666 --verify … through -b 6 -d 99699696 --verify
Set an ASK/Manchester config and dump, to establish ground truth: lf t55xx write -b 0 -d 00088040 --verify then lf t55xx detect then lf t55xx dump → all blocks read back correctly.
Switch to PSK1, the worst-affected modulation: lf t55xx write -b 0 -d 00081040 --verify
lf t55xx detect → block 0 is reported correctly.
lf t55xx dumptwice → most blocks come back rotated, and not the same way in both dumps.
Repeat with -b 0 -d 001070C0 (FSK2a) and -b 0 -d 00080040 (DIRECT/NRZ) for the other affected cases.
Expected behavior
lf t55xx dump should return the block contents, or fail. It should not return a rotation of the block contents indistinguishable from a correct read. Specifically, the bit offset used to extract a block should be derived from the buffer being decoded, not inherited from an earlier capture. If that is not possible for data blocks, the read should refuse when the demodulator's start position cannot be established.
lf t55xx write --verify should not report a successful write as a validation failure.
Screenshots
Not applicable. All output is text and included above.
Desktop
OS: macOS 26.6.1, Apple Silicon (aarch64)
Proxmark: generic device (AT91SAM7S512 Rev A)
Firmware platform: reproduced on bothPLATFORM=PM3GENERIC and PLATFORM=PM3RDV4 - see below.
hw version - the build all measurements below were taken on:
Note: the -dirty is not a local patch: git status in that tree showed only tools/ePassport/ePassport deleted, which is the macOS case-collision reported in #3509. git status over client/ armsrc/ common/ common_arm/ include/ was empty and no client or firmware source was modified.
[=] -------- LF Antenna ----------
[+] 125.00 kHz ........... 22.22 V
[+] 134.83 kHz ........... 14.44 V
[+] 117.65 kHz optimal.... 26.91 V
[+] Approx. Q factor measurement
[+] Frequency bandwidth... 6.6
[+] Peak voltage.......... 4.7
[!] Contradicting measures seem to indicate you're running a PM3_RDV4 firmware on a generic device
[!] False positives is possible but please check your setup
[+] LF antenna............ ok
[=] -------- HF Antenna ----------
[+] 13.56 MHz............. 61.23 V
[+] Approx. Q factor measurement
[+] Peak voltage.......... 10.7
[+] HF antenna ( ok )
Additional context
It is confined to the demodulators whose start point is not deterministic, which is what points at the cached offset rather than at signal quality. From DecodeT55xxBlock():
modulation
demod call
start determinism
ASK/Manchester
ASKDemod_ext(..., &ST)
anchored on the sequence terminator
Biphase
ASKbiphaseDemod(0, ...)
explicit offset = 0
FSK2a
FSKrawDemod(clk, inv, 10, 8, ...)
first fc transition found
DIRECT/NRZ
NRZrawDemod(..., maxErr=1, ...)
first detectable edge, not self-clocking
PSK1
PSKDemod(..., maxErr=6, ...)
phase-ambiguous, and the only demod given maxErr = 6
Measured across four T5577 tags, two manufacturers, six modulations, all on fb3ec70. Each tag: write the payload, set ASK/Manchester and dump for ground truth, then set each modulation and dump twice. Every field classified against all 31 rotations of the true value; unwritable blocks excluded. Figures are corrupted fields / fields scored:
modulation
blue-dual (Invengo 0x45)
copper-coin (SiCraft 0x39 ICR0)
orange-tag (SiCraft ICR2)
white-coin (SiCraft ICR0)
ASK/Manchester
0/24
0/24
0/16
0/24
Biphase
0/24
0/24
0/16
0/24
FSK2a mb6
4/24 rol1
0/24
3/16 ror1
7/24 ror1
FSK2a mb2
9/24 rol1
0/24
3/16 ror1
6/24 ror1
PSK1
11/12 †
22/24 ror4/ror5
14/16 ror5
22/24 ror4/ror5
DIRECT/NRZ
19/24 rol1
2/24
1/16
1/24
† half of blue-dual's PSK1 dumps returned no readable blocks at all - a total read failure rather than a misalignment.
Manchester and Biphase are clean on every tag - 0 of 88 fields each.
It is intermittent. Consecutive dumps of the same tag at the same placement disagree field by field.
It is ±1 bit, not a fixed off-by-one. Both directions appear on the same tag in the same run. PSK1 gives ror4andror5 on the same tag.
DIRECT is silicon-correlated (19/24 on Invengo, ≤2/24 on all three Silicon Craft tags); FSK2a is not - copper-coin is clean while white-coin, of identical manufacturer, part and IC revision (byte-identical page-1 b1 = E03900D0), reaches 7/24.
Firmware platform is a controlled variable, not a caveat. The default build is PLATFORM=PM3RDV4 (common_arm/Makefile.hal), and on generic hardware that makes hw tune print "Contradicting measures seem to indicate you're running a PM3_RDV4 firmware on a generic device". To remove that as an explanation, the whole probe was re-run on the same tag and the same commit with PLATFORM=PM3GENERIC (which clears the warning and drops the smartcard section from hw status):
config
PM3RDV4
PM3GENERIC
Manchester
clean 0/24
clean 0/24
Biphase
clean 0/24
clean 0/24
FSK2a mb6
7/24 ror1
4/24 ror1
FSK2a mb2
6/24 ror1
4/24 ror1
PSK1
22/24ror5×13 ror4×8
22/24ror5×13 ror4×4
DIRECT
1/24
1/24
PSK1 is 22 of 24 on both platforms, with the same dominant rotation. FSK2a moved (7→4, 6→4), which is consistent with it being the coupling-sensitive case rather than with the platform fixing anything. The controls stayed clean. Antenna coupling was equivalent across the two runs - hw tune read 22.22 V and 22.21 V at 125 kHz.
The 2026-07-30 DSP rework did not fix it.19cc98c reworked PSKDemod, FSKrawDemod, NRZrawDemod and ASKbiphaseDemod. The same tag measured on both sides of it:
config
v4.21611 (Apr)
fb3ec70 (Aug)
Manchester / Biphase
clean
clean
FSK2a mb6 / mb2
5/24, 17/24
7/24, 6/24
PSK1
22/24
22/24
No claim is made that the rate changed - the phenomenon is intermittent and that is one run per version.
On a fix. I have not sent a patch, deliberately: detect derives the offset by recognising a plausible configuration block, which works for block 0 and has nothing to latch onto on blocks 1–7, so "search per read" is not a drop-in. What the right design is - re-run detect internally, carry an alignment confidence out of the demodulator, or refuse when the start is not deterministic - seems a maintainer's call. Happy to test any candidate against the matrix above; the harness that produced it is scripted and re-runnable.
Related, but not duplicates
lf t55xx - modulation tests #149 (open) - lf t55xx modulation test success rates. That is about reads which fail; this is about reads which succeed with wrong data.
Making T5577 Downlink mode more transparent #377 (closed) - downlink-mode transparency. Not the bug, but it is why a block-0 write auto-runs detect, which is the mechanism behind the false --verify failures.
No genuine Atmel ATA5577 tested - all four tags are clones (Invengo, Silicon Craft).
In the FSK2a result, form factor, individual die and placement are mutually confounded. The data shows the trigger is not silicon but does not show what it is.
Describe the bug
lf t55xx dumpandlf t55xx rdblextract each 32-bit block at a bit offset cached from the lastlf t55xx detect, and never re-derive it from the buffer actually being decoded. When a later read's demodulation starts on a different bit boundary than the detect-time capture did, the returned word is a bit rotation of the true block - silently, with no error.detectis unaffected because it searches for the offset in the same buffer it just demodulated.client/src/cmdlft55xx.c(unchanged at masterfb3ec70):config.offsetis only ever assigned in the detect path (config.offset = tests[i].offset;), where it is found by searching for a plausible configuration block.Observed output - same tag, same placement, seconds apart.
001070C0was written to block 0,detectreads it correctly, the first dump is correct then the second dump returns0020E180, which is exactlyrol1(001070C0):Three consequences, in increasing severity:
lf t55xx dumpreturns wrong data that looks valid - no checksum, no warning.lf t55xx write --verifyreports successful writes as failures, because it validates by reading back through the same path (see the first line above). Users re-write, or conclude a tag is faulty.lf t55xx restoreof an affected dump writes the rotated data back permanently, so a tag can be made to hold a rotated copy of its own contents. This turns a read bug into data loss.To Reproduce
A5A5A5A5lands on itself under many wrong rotations and hides the bug:lf t55xx write -b 1 -d 1D996666 --verify… through-b 6 -d 99699696 --verifylf t55xx write -b 0 -d 00088040 --verifythenlf t55xx detectthenlf t55xx dump→ all blocks read back correctly.lf t55xx write -b 0 -d 00081040 --verifylf t55xx detect→ block 0 is reported correctly.lf t55xx dumptwice → most blocks come back rotated, and not the same way in both dumps.Repeat with
-b 0 -d 001070C0(FSK2a) and-b 0 -d 00080040(DIRECT/NRZ) for the other affected cases.Expected behavior
lf t55xx dumpshould return the block contents, or fail. It should not return a rotation of the block contents indistinguishable from a correct read. Specifically, the bit offset used to extract a block should be derived from the buffer being decoded, not inherited from an earlier capture. If that is not possible for data blocks, the read should refuse when the demodulator's start position cannot be established.lf t55xx write --verifyshould not report a successful write as a validation failure.Screenshots
Not applicable. All output is text and included above.
Desktop
PLATFORM=PM3GENERICandPLATFORM=PM3RDV4- see below.hw version- the build all measurements below were taken on:Note: the
-dirtyis not a local patch:git statusin that tree showed onlytools/ePassport/ePassportdeleted, which is the macOS case-collision reported in #3509.git statusoverclient/ armsrc/ common/ common_arm/ include/was empty and no client or firmware source was modified.hw status:hw tune(bare antenna, nothing on the pad):Additional context
It is confined to the demodulators whose start point is not deterministic, which is what points at the cached offset rather than at signal quality. From
DecodeT55xxBlock():ASKDemod_ext(..., &ST)ASKbiphaseDemod(0, ...)offset = 0FSKrawDemod(clk, inv, 10, 8, ...)NRZrawDemod(..., maxErr=1, ...)PSKDemod(..., maxErr=6, ...)maxErr = 6Measured across four T5577 tags, two manufacturers, six modulations, all on
fb3ec70. Each tag: write the payload, set ASK/Manchester and dump for ground truth, then set each modulation and dump twice. Every field classified against all 31 rotations of the true value; unwritable blocks excluded. Figures are corrupted fields / fields scored:(Invengo
0x45)(SiCraft
0x39ICR0)(SiCraft ICR2)
(SiCraft ICR0)
rol1ror1ror1rol1ror1ror1ror4/ror5ror5ror4/ror5rol1† half of blue-dual's PSK1 dumps returned no readable blocks at all - a total read failure rather than a misalignment.
ror4andror5on the same tag.copper-coinis clean whilewhite-coin, of identical manufacturer, part and IC revision (byte-identical page-1b1 = E03900D0), reaches 7/24.Firmware platform is a controlled variable, not a caveat. The default build is
PLATFORM=PM3RDV4(common_arm/Makefile.hal), and on generic hardware that makeshw tuneprint "Contradicting measures seem to indicate you're running a PM3_RDV4 firmware on a generic device". To remove that as an explanation, the whole probe was re-run on the same tag and the same commit withPLATFORM=PM3GENERIC(which clears the warning and drops the smartcard section fromhw status):PM3RDV4PM3GENERICror1ror1ror1ror1ror5×13ror4×8ror5×13ror4×4PSK1 is 22 of 24 on both platforms, with the same dominant rotation. FSK2a moved (7→4, 6→4), which is consistent with it being the coupling-sensitive case rather than with the platform fixing anything. The controls stayed clean. Antenna coupling was equivalent across the two runs -
hw tuneread 22.22 V and 22.21 V at 125 kHz.The 2026-07-30 DSP rework did not fix it.
19cc98creworkedPSKDemod,FSKrawDemod,NRZrawDemodandASKbiphaseDemod. The same tag measured on both sides of it:v4.21611(Apr)fb3ec70(Aug)No claim is made that the rate changed - the phenomenon is intermittent and that is one run per version.
On a fix. I have not sent a patch, deliberately:
detectderives the offset by recognising a plausible configuration block, which works for block 0 and has nothing to latch onto on blocks 1–7, so "search per read" is not a drop-in. What the right design is - re-run detect internally, carry an alignment confidence out of the demodulator, or refuse when the start is not deterministic - seems a maintainer's call. Happy to test any candidate against the matrix above; the harness that produced it is scripted and re-runnable.Related, but not duplicates
lf t55xxmodulation test success rates. That is about reads which fail; this is about reads which succeed with wrong data.detect, which is the mechanism behind the false--verifyfailures.Limitations