
Raggi X della latenza per hardware non documentato
Uno strumento esplorativo per il timing di MMIO — cronometra qualsiasi indirizzo fisico e disseziona l' hardware dalla latenza.

Sorprendentemente utile per il reverse engineering dell'hardware, il fingerprinting degli hypervisor, l'analisi dell'attività dei dispositivi tramite canali laterali, la caratterizzazione dei registri, la calibrazione di trigger malevoli e la creazione di istruzioni macchina oscenamente lunghe.
Il primo megabyte di memoria fisica è un semplice esempio con cui iniziare, anche se la sua struttura è già ben nota.

I confini di latenza ci permettono di suddividere lo spazio degli indirizzi, senza fare affidamento sui layout riportati.
sudo ./mmiotic --start-address 0x0 --end-address 0x100000 --stride 4 --count 20 --quiet-mmap0x9FFFF a ~380 cy, poi
il buco video da 128 KB, che si divide in due a 0xB0000. Il cambiamento
di varianza a 0x20000 potrebbe indicare un page walk diverso per la pagina null.A0000–AFFFF: lenta e irregolare (996 cy, stdev 327), instradata verso la
Radeon accesa ma in idle. B0000–BFFFF: veloce e rigida (780 cy, stdev 3.2,
legge ffffffff), non reclamata da nessuno. Dati dall'aspetto simile, ma un
divario di varianza di 100x.C0000–FFFFF: /proc/iomem dice "System ROM", ma la scansione mostra latenza
DRAM, non velocità flash — il BIOS è shadowato nella DRAM.Scansiona uno spazio di configurazione del root complex (00:00.0, 4 KB) per individuare valori anomali di
latenza rispetto a un minimo piatto di ~675 cicli:

La latenza della mailbox è significativamente più alta rispetto ai dati circostanti, e i picchi duplicati e le varianze equivalenti ci permettono di associare registri funzionalmente simili.
sudo ./mmiotic --start-address 0xf8000000 --end-address 0xf8001000 --stride 4 --count 2000xe4 (1218 cy, valore 80e3110b) e
0xa4 (1199 cy, valore deadbeef). e4 è un doorbell documentato; a4 non è
documentato.e4 è pubblico.deadbeef viene letto come un sentinel non inizializzato/di errore — stessa
mailbox, a4 non implementato o alimentato con input non valido.Latenze accuratamente selezionate possono talvolta essere usate in insoliti scenari di exploitation (MCHAMMER, smiiiiiiiiiiiiiiii):

Qui una Radeon in idle e senza driver trasforma una lettura allineata da 4 byte in uno stallo di ~100.000 cicli.
sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e00100 --stride 4 --count 50 — spazza l'inizio della BAR della GPU (0x90e00000, 256 KB). 0x90e00008 costa 110.152 cy; 0x90e00018,
16 byte più avanti, è di nuovo veloce a 1.523 — per-registro, non per-pagina.sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e40000 --stride 4 --count 1 --binary — --binary sonda in ordine bit-reversal, quindi l'intera
apertura da 256 KB viene coperta uniformemente dopo 1.012 sonde, mappando un
blocco contiguo da 48 KB in cui ogni registro è lento.Idealmente, leggere un indirizzo fisico sarebbe un'operazione relativamente sicura, ma
mmiotic è particolarmente bravo a scoprire accidentalmente le eccezioni:

Ad esempio, sulla piattaforma di cui sopra, una lettura da 1 byte di 0xdc5003b0 — offset
0x3b0 di una BAR di registri della iGPU Zen 4 senza driver (Region 5, 0xdc500000, 512 KB)
— resetta il sistema in modo affidabile.
sudo ./mmiotic --address 0xdc5003b0 --size 1 --count 1. Nessun output; la macchina
si riavvia.0x3ac e 0x3b4 ai lati leggono 00000000 a ~3.200
cicli e sono innocui.0x3a0–0x3fc trova 7 dword velenose intervallate da 17
sicure.sudo busybox devmem 0xdc5003b0 32 e sudo dd if=/dev/mem bs=1 count=1 skip=$((0xdc5003b0))
mandano giù la macchina se preferisci saltare il passaggio intermedio.[!WARNING] Alcune piattaforme si resettano quando specifiche regioni di indirizzi vengono sondate da
mmiotic. Fai attenzione a dove lo usi.
| Opzione | Nomi |
|---|---|
-b/-d/-f/-r | PCI --bus/--device/--function/--register — decodificati rispetto alla base ECAM |
-o, --offset <n> | offset dalla base MMIO (salta la decodifica B/D/F) |
-A, --address <n> | un singolo indirizzo fisico; imposta implicitamente la base della regione |
-a/-z | --start-address/--end-address — un intervallo fisico; implica --scan |
La base e la dimensione ECAM vengono rilevate automaticamente da ACPI MCFG
(/sys/firmware/acpi/tables/MCFG). Puoi sovrascriverle con -M, --mmio-base /
-Z, --mmio-size.
| Opzione | Effetto |
|---|---|
-S, --scan | percorre tutti gli indirizzi nella regione target |
-t, --stride <n> | passo tra gli indirizzi (predefinito: 4) |
-n, --limit <n> | si ferma dopo questo numero di indirizzi |
--binary | sonda in ordine bit-reversal — dopo k sonde l'intervallo ha una copertura uniforme con granularità ~range/k (vedi l'avviso sopra) |
-x, --limited | intervallo di registri limitato (0x00–0xff vs 0x000–0xfff) |
-e, --skip | salta le funzioni che leggono 0xffffffff all'offset 0 (dispositivi assenti) |
-I, --iomem | scansiona ogni regione di primo livello non–System-RAM in /proc/iomem |
-R, --ioregion <name> | scansiona le regioni di /proc/iomem la cui etichetta corrisponde a <name>, a qualsiasi profondità |
--find-target/--find-longest trasformano la scansione in ricerca:
| Opzione | Effetto |
|---|---|
-F, --find-target <s> | trova un indirizzo il cui tempo di accesso raggiunge s secondi, quindi aumenta la larghezza (4b non allineati → 8/16/32/64/512b) per spingerlo più in alto |
-G, --find-longest | stessa ricerca, ma esaurisce ogni candidato invece di fermarsi al primo risultato |
-B, --fallbacks <n> | candidati portati nella fase di escalation (predefinito: 10) |