Skip to content

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:

pml4_base = CR3 & 0x000FFFFFFFFFF000   # bits MaxPhysAddr:12, low 12 bits cleared

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.

References