
أشعة سينية لزمن استجابة العتاد غير الموثق
أداة استكشافية لتوقيت MMIO — قِس زمن أي عنوان فيزيائي، وشَرِّح العتاد انطلاقًا من زمن الاستجابة.

مفيدة بشكل غير متوقع في الهندسة العكسية للعتاد، وبصمات الهايبرفايزر، واستغلال القنوات الجانبية لمراقبة نشاط الأجهزة، وتوصيف التسجيلات، ومعايرة المشغِّلات الخبيثة، وصياغة تعليمات آلة طويلة بشكل فاحش.
الميغابايت الأولى من الذاكرة الفيزيائية مثال سهل للبدء به، حتى لو كان تركيبها معروفًا جيدًا مسبقًا.

حدود زمن الاستجابة تتيح لنا تقسيم فضاء العناوين دون الاعتماد على التخطيطات المُبلَّغ عنها.
sudo ./mmiotic --start-address 0x0 --end-address 0x100000 --stride 4 --count 20 --quiet-mmap0x9FFFF عند ~380 دورة، ثم فجوة الفيديو البالغة 128 كيلوبايت، والتي تنقسم إلى قسمين عند 0xB0000. قد يشير تغيّر التباين عند 0x20000 إلى مسار تنقّل صفحات مختلف للصفحة الصفرية.A0000–AFFFF: بطيء ومتذبذب (996 دورة، والانحراف المعياري 327)، ويُوجَّه إلى Radeon المزوَّد بالطاقة والخامل. B0000–BFFFF: سريع وثابت (780 دورة، والانحراف المعياري 3.2، يقرأ ffffffff)، ولا يطالب به أحد. بيانات تبدو متشابهة، لكن الفجوة في التباين تبلغ 100 ضعف.C0000–FFFFF: يقول /proc/iomem «System ROM»، لكن الفحص يُظهر زمن استجابة DRAM وليس سرعة الفلاش — إذ إن BIOS مُظلَّل داخل DRAM.افحص فضاء إعداد root-complex (00:00.0، 4 كيلوبايت) بحثًا عن القيم الشاذة في زمن الاستجابة مقابل أرضية مسطّحة تبلغ ~675 دورة:

زمن استجابة صندوق البريد أعلى بكثير من البيانات المحيطة، وتكرار القمم وتكافؤ التباينات يتيحان لنا مطابقة تسجيلات متشابهة وظيفيًا.
sudo ./mmiotic --start-address 0xf8000000 --end-address 0xf8001000 --stride 4 --count 2000xe4 (1218 دورة، القيمة 80e3110b) و0xa4 (1199 دورة، القيمة deadbeef). e4 جرس باب (doorbell) موثّق؛ أما a4 فغير موثّق.e4.deadbeef كقيمة حارسة (sentinel) تدل على حالة غير مهيَّأة/خطأ — صندوق البريد نفسه، لكن a4 غير مُنفَّذ أو يتلقى مدخلات غير صالحة.يمكن أحيانًا استخدام زمن استجابة مُنتقى بعناية في سيناريوهات استغلال غير مألوفة (MCHAMMER، smiiiiiiiiiiiiiiii):

هنا، يحوّل Radeon خامل وبلا برنامج تشغيل (driver) قراءة واحدة محاذاة من 4 بايتات إلى تعليق (stall) يبلغ ~100,000 دورة.
sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e00100 --stride 4 --count 50 — امسح رأس BAR الخاصة بوحدة معالجة الرسوم (GPU) (0x90e00000، 256 كيلوبايت). تكلّف 0x90e00008 110,152 دورة؛ أما 0x90e00018، التي تبعد 16 بايتًا، فتعود سريعة عند 1,523 — لكل تسجيل وليس لكل صفحة.sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e40000 --stride 4 --count 1 --binary — يفحص --binary بترتيب عكس البتات، لذا تُغطَّى نافذة الـ256 كيلوبايت كاملة تغطية موحّدة بعد 1,012 عملية فحص، ليرسم كتلة متصلة من 48 كيلوبايت يكون فيها كل تسجيل بطيئًا.من الناحية المثالية، سيكون قراءة عنوان فيزيائي عملية آمنة نسبيًا، لكن mmiotic بارع خصوصًا في العثور مصادفةً على الاستثناءات:

على سبيل المثال، على المنصة أعلاه، قراءة 1 بايت من 0xdc5003b0 — الإزاحة 0x3b0 من BAR لتسجيلات iGPU في معالج Zen 4 دون برنامج تشغيل (المنطقة 5، 0xdc500000، 512 كيلوبايت) — تعيد تشغيل النظام بشكل موثوق.
sudo ./mmiotic --address 0xdc5003b0 --size 1 --count 1. لا مخرجات؛ يُعاد تشغيل الجهاز.0x3ac و0x3b4 على الجانبين تقرآن 00000000 عند ~3,200 دورة، وليستا ضارّتين.0x3a0–0x3fc يعثر على 7 كلمات مزدوجة سامّة متداخلة مع 17 سليمة.sudo busybox devmem 0xdc5003b0 32 وsudo dd if=/dev/mem bs=1 count=1 skip=$((0xdc5003b0)) تُسقطان الجهاز إذا فضّلت تجاوز الوسيط.[!WARNING] ستعيد بعض المنصات تشغيل نفسها عند فحص مناطق عناوين محددة بواسطة
mmiotic. كن حذرًا في المكان الذي تستخدمه فيه.
تُكتشف قاعدة ECAM وحجمها تلقائيًا من ACPI MCFG (/sys/firmware/acpi/tables/MCFG). يمكن تجاوزهما باستخدام -M, --mmio-base / -Z, --mmio-size.
يحوّل --find-target/--find-longest الفحص إلى بحث:
| الخيار | التأثير |
|---|---|
-F, --find-target <s> | العثور على عنوان يبلغ زمن وصوله s ثانية، ثم تصعيد العرض (4b غير محاذاة → 8/16/32/64/512b) لدفعه إلى أعلى |
-G, --find-longest | البحث نفسه، لكن مع استنفاد كل مرشح بدل التوقف عند أول إصابة |
b/d/f.o.l: 00:02:00.00.4 address: 00000000f0100000 min: 312 max: 480 stdev: 2.1 dynamic: 0 value: 8086abcd
تُلحق -T عدد الدورات باللاحقة cy وتُدرج زوج زمن min/max مقيَّسًا (تطبع -N تلك القيم كنانوثانية خام):
b/d/f.o.l: 00:02:00.00.4 address: 00000000f0100000 min: 312 cy max: 480 cy ( 104 ns/ 160 ns) stdev: 2.1 dynamic: 0 value: 8086abcd
البناء:
make
يعمل بصلاحيات الجذر (root) للوصول إلى /dev/mem.
إذا رأيت: mmap ... Operation not permitted، فجرّب الإقلاع مع iomem=relaxed لرفع CONFIG_STRICT_DEVMEM:
# /etc/default/grub
GRUB_CMDLINE_LINUX="iomem=relaxed nopat"
ثم نفّذ sudo update-grub وأعد التشغيل.
استُخدم mmiotic لتطوير مجموعة متنوعة من الأبحاث الداخلية والخارجية، أحيانًا بطرق غير متوقعة. بعض الأمثلة على تطبيقات mmiotic:
MCHAMMER: يعاير mmiotic استثناء فحص آلة (machine check exception) مؤجَّلًا لتسليم إشارات MC# بدقة إلى البيئات المحمية.
smiiiiiiiiiiiiiiii: يحلّ mmiotic مسألة التعليمة عالية زمن الاستجابة لكسر نقطة التقاء SMM.
The Assembly Hall of Shame: يُستخدم mmiotic على نطاق واسع من أجل المشكلة المهمة المتمثلة في إضعاف الأداء (performance deoptimization).
mmiotic جهد بحثي من Christopher Domas (@xoreaxeaxeax).
| الخيار | الأسماء |
|---|
-b/-d/-f/-r | PCI --bus/--device/--function/--register — تُفكَّك شفرتها مقابل قاعدة ECAM |
-o, --offset <n> | الإزاحة من قاعدة MMIO (تتجاوز فك شفرة B/D/F) |
-A, --address <n> | عنوان فيزيائي واحد؛ يضبط قاعدة المنطقة ضمنيًا |
-a/-z | --start-address/--end-address — نطاق فيزيائي؛ يستلزم --scan |
| الخيار | التأثير |
|---|
-S, --scan | تجوال في جميع عناوين المنطقة المستهدفة |
-t, --stride <n> | الخطوة بين العناوين (الافتراضي: 4) |
-n, --limit <n> | التوقف بعد هذا العدد من العناوين |
--binary | افحص بترتيب عكس البتات — بعد k عملية فحص يكتسب النطاق تغطية موحّدة بدقة تفصيل تبلغ ~range/k (انظر التحذير أعلاه) |
-x, --limited | نطاق تسجيلات محدود (0x00–0xff مقابل 0x000–0xfff) |
-e, --skip | تجاوز الوظائف التي تقرأ 0xffffffff عند الإزاحة 0 (الأجهزة الغائبة) |
-I, --iomem | فحص كل منطقة عليا غير System-RAM في /proc/iomem |
-R, --ioregion <name> | فحص مناطق /proc/iomem التي يطابق وسمها <name>، مهما كان عمقها |
-B, --fallbacks <n> | المرشحون المنقولون إلى مرحلة التصعيد (الافتراضي: 10) |
| الخيار | التأثير |
|---|
-s, --size <n> | بايتات لكل وصول: 1 / 2 / 4 (الافتراضي) / 8 / 16 (XMM) / 32 (YMM) / 64 (ZMM) / 512 (fxrstor). الأحجام الأكبر من 4 خارج المواصفة لكنها تعمل على العتاد المختبر؛ عروض AVX تتطلب AVX / AVX-512F |
-c, --count <n> | عينات لكل عنوان (الافتراضي: 1)؛ ويُبلَّغ عن الحد الأدنى |
-L, --lock | قياس زمن RMW مقفلة: lock xadd (الأحجام 1/2/4/8) أو lock cmpxchg16b (الحجم 16). يعيد كتابة القيمة |
-g, --gather | قياس زمن gather متجهي؛ يختار --size 16/32/64 كلاً من XMM/YMM/ZMM (AVX-512) |
-w, --write-read | التقاط زمن استجابة الكتابة بقياس زمن قراءة يجب أن تلاحظ كتابة منشورة (posted write) سابقة — انظر أدناه |
-E, --enter (--enter-2, --enter-3) | دفع دفعة من الوصولات يصل عددها إلى 30 انطلاقًا من تعليمة enter $0, $31 واحدة — انظر أدناه |
-k, --continue | عند خطأ fxrstor، تجاهل تلك العينة وواصل الفحص |
| الخيار | التأثير |
|---|
-C, --min-cycles <n> | طباعة النتائج ذات min_cycles >= n فقط |
-T, --time | إظهار النانوثانية إلى جانب الدورات (يكتشف تردد TSC) |
-N, --nanosecond | مع --time، طباعة نانوثانية خام دون تحويل الوحدات |
-P, --progress | تقدّم الفحص لحظيًا على stderr |
-p, --processor <n> | التثبيت على معالج منطقي n (الافتراضي: 0) — يقلل ضجيج المؤقّت |
-u, --unbound | عدم التثبيت على أي نواة |
--lazy-mmap | تخطيط نوافذ بسعة 2 جيجابايت عند الطلب؛ مطلوب للمناطق الأكبر من 2 جيجابايت |
--quiet-mmap | كتم ضجيج «mmap failed» الصادر عن المناطق غير القابلة للوصول |
| الحقل | المعنى |
|---|
b/d/f.o.l | الناقل/الجهاز/الوظيفة، إزاحة التسجيل، حجم الوصول |
offset | الإزاحة من قاعدة MMIO — تستبدل b/d/f.o.l عندما جاء الهدف من -o/-A/-a+-z |
address | عنوان فيزيائي كامل 64-بت |
min/max | أسرع وأبطأ وصول شوهد، بالدورات |
stdev | الانحراف المعياري لعدد الدورات المُعيَّنة |
dynamic | 1 إذا تغيّرت القيمة في أي نقطة عبر العينات |
value | القيمة المقروءة — للأحجام الأكبر من 8 بايتات، أول 32 بايتًا ككلمات رباعية (qwords) مفصولة بمسافات |
faults | يُضاف فقط إذا حدث خطأ في الوصول |