Guest CR3 / kpgd resolution¶
Bir guest'in top-level page-table base'inin (CR3 / kernel page global directory) physical address'ini guest dışından bulmak; böylece bir introspection engine, herhangi bir guest virtual address'i translate etmek için gereken root'a sahip olur.
Mechanism¶
Note
Her x86 address space, top-level paging structure'ın physical address'ini tutan CR3'te köklenir (x86-64'te PML4, Linux'ta page global directory / PGD, Windows'ta DirectoryTableBase). Bir process çalışırken CR3, o process'in PGD'sinin physical address'iyle yüklenir; MMU virtual'dan physical'a translate etmek için oradan walk eder. Guest dışından herhangi bir virtual-address introspection yapmak için önce geçerli bir CR3 elde etmelisin — onsuz bir guest virtual address anlamsızdır, çünkü farklı address space'lerdeki aynı VA'lar farklı physical frame'lere map'lenir.
Bu, semantic gap üzerindeki ilk köprüdür: bir VMM ham physical frame'leri görür, guest'in "şu process'in address space'i" kavramını değil. Kernel page directory base'ini (kpgd / System process'inin DTB'si) çözmek, sonraki tüm kernel introspection'ı sabitler, çünkü kernel mapping'leri paylaşımlı ve stabildir. kpgd'den bir introspection engine kernel structure'larını okuyabilir, process'leri enumerate edebilir ve per-process walk'lar için her process'in kendi CR3'ünü toplayabilir. Bu root'u tüketen translation için bkz. guest page-table walk.
Walkthrough¶
Bir CR3 için iki geniş kaynak vardır ve LibVMI gibi araçlar ikisini de fallback'lerle kullanır.
(a) Architectural read. Driver/hypervisor bir vCPU'nun register'larını okuyabiliyorsa, canlı CR3 doğrudan erişilebilirdir. Table base'i elde etmek için control/attribute bit'lerini maskeleyin — yalnızca physical-frame bit'leri önemli:
Bu, vCPU'nun o an hangi address space'inde olduğunu verir ki bu arbitrary bir process olabilir. Stabil bir anchor için genellikle kernel/System directory base'ini istersin.
(b) Kernel directory base'inin heuristic / symbol tabanlı keşfi. LibVMI'ın Windows path'i çeşitli yöntemleri gösterir (bunları sırayla, fallback'lerle dener):
get_kpgd_method0 : scan physical memory for the System process (PID 4) via
PsActiveProcessHead, walk the list, read its page-dir base
get_kpgd_method1 : resolve kernel symbol PsInitialSystemProcess, translate it,
read DirectoryTableBase from the EPROCESS/_KPROCESS
get_kpgd_method2 : locate the System process (cached or via find_eprocess),
read the page directory at offset windows->pdbase_offset
DirectoryTableBase offset'inin kendisi profile üzerinden bakılır, örn.
json_profile_lookup(vmi, "_KPROCESS", "DirectoryTableBase", &pdbase_offset)
(tarihsel olarak eski Windows'larda base+0x18 civarında, ama version'a bağlı —
hardcode etmeyin). Linux'ta benzer root mm->pgd'dir, yani PGD'nin virtual
address'i; CR3 değerini elde etmek için physical'a çevrilir (virt_to_phys).
Warning
CR3 bir thread'i değil, bir address space'i tanımlar — bir process'in thread'leri bir PGD'yi, dolayısıyla bir CR3'ü paylaşır. Ayrıca KPTI/meltdown mitigation'ları kernel ve user yarılarına ayrı page-table root'ları verir ve KASLR kernel directory'nin nerede yaşadığını randomize eder; bu yüzden naif "CR3'ü bir kez oku" veya fixed-offset scan'leri yanlış (user) table'a düşebilir ya da kernel root'unu tamamen kaçırabilir.
Detection¶
- Bir guest, guest dışındaki CR3 read'lerini doğrudan gözlemleyemez (bunlar VMX root'ta, guest tarafından görünür bir side effect olmadan gerçekleşir). Dolaylı ipuçları, introspection kaynaklı pause'lar veya CR-access VM-exit / CR3-load exiting'in etkinleştirilmiş olmasıdır; timing'e duyarlı bir guest bunu context-switch latency'sinden çıkarabilir.
- VMM'i çalıştıran defender'lar için otoriter görünüm, introspection engine'in hangi CR3 değerlerini ve nasıl çözdüğüne dair kendi log'larıdır.
Mitigation¶
(Anti-introspection perspektifi; savunma amaçlı deployment'larda bu primitive bir tehdit değil, hedeftir.)
- KPTI, KASLR ve per-process address-space randomization, fixed-offset kpgd scan'lerinin maliyetini artırır ve symbol/profile tabanlı çözümü zorunlu kılar.
- Bir guest rootkit, bu heuristic'lerin okuduğu structure'ları desynchronize edebilir (System process'i unlink etmek, DirectoryTableBase'i forge etmek), bu yüzden sağlam engine'ler tek bir yönteme güvenmek yerine birden fazla yöntemi cross-check eder.
- Savunma açısından, daha kolay spoof edilen physical-memory scanning yerine CR3'ü vCPU state'inden architectural olarak okumayı, validate edilmiş kernel symbol'ları ile birlikte tercih edin.