
Latenz-Röntgen für undokumentierte Hardware
Ein exploratives Werkzeug für MMIO-Timing — miss die Latenz einer beliebigen physischen Adresse und zerlege die Hardware anhand der Latenz.

Unerwartet nützlich für Hardware-Reverse-Engineering, Hypervisor-Fingerprinting, Side-Channeling von Geräteaktivitäten, Registercharakterisierung, Kalibrierung bösartiger Auslöser und das Erzeugen obszön langer Maschinenbefehle.
Das erste Megabyte des physischen Speichers ist ein einfaches Beispiel für den Einstieg, auch wenn seine Struktur bereits gut bekannt ist.

Die Latenzgrenzen erlauben es uns, den Adressraum zu unterteilen, ohne uns auf gemeldete Layouts zu verlassen.
sudo ./mmiotic --start-address 0x0 --end-address 0x100000 --stride 4 --count 20 --quiet-mmap0x9FFFF bei ~380 cy, dann das 128-KB-Video-Loch, das sich bei 0xB0000 in zwei Teile teilt. Die Änderung der Varianz bei 0x20000 könnte auf einen anderen Page Walk für die Null-Seite hindeuten.A0000–AFFFF: langsam und zittrig (996 cy, stdev 327), zum stromversorgten, aber im Leerlauf befindlichen Radeon geleitet. B0000–BFFFF: schnell und starr (780 cy, stdev 3.2, liest ffffffff), von niemandem beansprucht. Ähnlich aussehende Daten, aber eine 100-fache Varianzlücke.C0000–FFFFF: /proc/iomem sagt „System ROM“, aber der Scan zeigt DRAM-Latenz, nicht Flash-Geschwindigkeit — das BIOS wird in den DRAM gespiegelt.Scanne einen Root-Complex-Konfigurationsraum (00:00.0, 4 KB) nach Latenz-Ausreißern gegenüber einem flachen Boden von ~675 Zyklen:

Die Mailbox-Latenz ist deutlich höher als die umgebenden Daten, und die doppelten Spitzen und gleichwertigen Varianzen ermöglichen es uns, funktional ähnliche Register zuzuordnen.
sudo ./mmiotic --start-address 0xf8000000 --end-address 0xf8001000 --stride 4 --count 2000xe4 (1218 cy, Wert 80e3110b) und 0xa4 (1199 cy, Wert deadbeef). e4 ist eine dokumentierte Doorbell; a4 ist undokumentiert.e4 öffentlich ist.deadbeef liest sich wie ein Sentinel für „nicht initialisiert/Fehler“ — gleiche Mailbox, a4 nicht implementiert oder mit ungültiger Eingabe gefüttert.Sorgfältig ausgewählte Latenzen können manchmal in ungewöhnlichen Exploit-Szenarien eingesetzt werden (MCHAMMER, smiiiiiiiiiiiiiiii):

Hier verwandelt ein im Leerlauf befindlicher, treiberloser Radeon einen einzelnen ausgerichteten 4-Byte-Read in einen Stillstand von ~100.000 Zyklen.
sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e00100 --stride 4 --count 50 — überstreiche den Kopf der GPU-BAR (0x90e00000, 256 KB). 0x90e00008 kostet 110.152 cy; 0x90e00018, 16 Bytes weiter, ist mit 1.523 wieder schnell — pro Register, nicht pro Seite.sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e40000 --stride 4 --count 1 --binary — --binary testet in Bitumkehr-Reihenfolge, sodass die gesamte 256-KB-Apertur nach 1.012 Sondierungen gleichmäßig abgedeckt ist und ein zusammenhängender 48-KB-Block kartiert wird, in dem jedes Register langsam ist.Idealerweise wäre das Lesen einer physischen Adresse ein relativ sicherer Vorgang, aber mmiotic ist besonders gut darin, versehentlich die Ausnahmen zu finden:

Zum Beispiel setzt auf der obigen Plattform ein 1-Byte-Read von 0xdc5003b0 — Offset 0x3b0 einer treiberlosen Zen-4-iGPU-Register-BAR (Region 5, 0xdc500000, 512 KB) — das System zuverlässig zurück.
sudo ./mmiotic --address 0xdc5003b0 --size 1 --count 1. Keine Ausgabe; die Kiste startet neu.0x3ac und 0x3b4 auf beiden Seiten lesen 00000000 bei ~3.200 cy und sind harmlos.0x3a0–0x3fc findet 7 schädliche Dwords, die mit 17 sicheren verschachtelt sind.sudo busybox devmem 0xdc5003b0 32 und sudo dd if=/dev/mem bs=1 count=1 skip=$((0xdc5003b0)) bringen die Kiste zu Fall, wenn du den Mittelsmann lieber überspringst.[!WARNING] Einige Plattformen setzen zurück, wenn bestimmte Adressbereiche von
mmioticuntersucht werden. Sei vorsichtig, wo du dies einsetzt.
| Option | Namen |
|---|---|
-b/-d/-f/-r | PCI --bus/--device/--function/--register — gegen die ECAM-Basis dekodiert |
-o, --offset <n> | Offset von der MMIO-Basis (überspringt die B/D/F-Dekodierung) |
-A, --address <n> | eine physische Adresse; setzt die Regionsbasis implizit |
-a/-z | --start-address/--end-address — ein physischer Bereich; impliziert --scan |
Die ECAM-Basis und -Größe werden automatisch aus ACPI MCFG erkannt (/sys/firmware/acpi/tables/MCFG). Überschreibe sie mit -M, --mmio-base / -Z, --mmio-size.
| Option | Effekt |
|---|---|
-S, --scan | alle Adressen in der Zielregion durchlaufen |
-t, --stride <n> | Schritt zwischen Adressen (Standard: 4) |
-n, --limit <n> | nach dieser Anzahl von Adressen anhalten |
--binary | in Bitumkehr-Reihenfolge prüfen — nach k Prüfungen hat der Bereich eine gleichmäßige Abdeckung mit ~range/k-Granularität (siehe Warnung oben) |
-x, --limited | eingeschränkter Registerbereich (0x00–0xff statt 0x000–0xfff) |
-e, --skip | Funktionen überspringen, die bei Offset 0 0xffffffff lesen (nicht vorhandene Geräte) |
-I, --iomem | jeden Top-Level-Bereich in /proc/iomem scannen, der kein System-RAM ist |
-R, --ioregion <name> | /proc/iomem-Bereiche scannen, deren Bezeichnung auf <name> passt, in jeder Tiefe |
--find-target/--find-longest verwandeln das Scannen in eine Suche:
| Option | Effekt |
|---|---|
-F, --find-target <s> | finde eine Adresse, deren Zugriffszeit s Sekunden erreicht, und steigere dann die Breite (unausgerichtetes 4b → 8/16/32/64/512b), um sie weiter zu erhöhen |
-G, --find-longest | gleiche Suche, aber jeden Kandidaten ausschöpfen, statt beim ersten Treffer abzubrechen |
-B, --fallbacks <n> | Kandidaten, die in die Eskalationsphase übernommen werden (Standard: 10) |