Skip to content

Guest state reconstruction (semantic gap bridging)

Bir VMM'in gördüğü ham RAM ve register byte'larından yüksek seviyeli OS abstraction'larını — process list'leri, loaded module'ler, page table'lar — guest kernel'in data structure'ları ve symbol'leri hakkındaki out-of-band bilgiyi uygulayarak yeniden inşa etmek. Bu translation problemi "semantic gap"tir.

Mechanism

Gap neden var

Bir virtual machine monitor, guest'i hardware abstraction seviyesinde gözlemler: ham byte olarak physical memory, architectural register'lar (CR3, RIP, segment/descriptor state) ve instruction trap'leri. Bir "process", bir "thread", bir "open file" veya bir "loaded driver" kavramına doğal olarak sahip değildir — bunlar tamamen guest OS tarafından tanımlanan software convention'larıdır. Garfinkel ve Rosenblum virtual machine introspection'ı (bir VM'in runtime state'ini dışarıdan incelemek, örn. intrusion detection için) ortaya koydu ve VMM'in low-level görünümünü anlamlı bir şeye çevirmenin zorluğu semantic gap problemi olarak bilinir oldu.

Gap'i köprülemek, guest OS'in internal layout'unu external bilgi olarak içe aktarmayı gerektirir:

  • Kernel symbol'leri / offset'ler: init_task (Linux) veya PsActiveProcessHead (Windows) address'i ve task_struct / EPROCESS içindeki field'ların byte offset'leri (örn. list-link, name ve PID field'ları). Linux'ta bunlar System.map / kernel debug info'dan; Windows'ta PDB symbol'lerinden gelir. Version'a özeldirler ve patch'ler ile build'ler arasında kayarlar.
  • Object traversal: bir head pointer ve bir field offset ile monitor, kernel'in process object'lerinin linked list'ini doğrudan guest RAM'den walk eder ve canlı process list'ini, tıpkı in-guest bir enumerator gibi — ama in-guest koda güvenmeden — yeniden inşa eder.
  • Address translation: bir process'in virtual memory'sini okumak için monitor, page-table walk'u kendisi yapmalıdır; guest'in CR3'ünü (directory base / KPGD) kullanarak guest-virtual → guest-physical'ı çözer, sonra gerçek host frame'lerine ulaşmak için EPT/host paging'i kullanır.

Erken sistemler mevcut forensic tooling'e yaslandı — Garfinkel & Rosenblum'un introspection'ı OS structure'larını VMM'den okumak için crash utility'sini kullandı — ve modern framework'ler (Volatility, LibVMI), process tree'sini ve kernel object list'lerini çıkarabilmek için tam olarak bu symbol ve offset'leri kodlayan per-OS "profile"lar sunar.

Reconstruction yalnızca offset verisi kadar güvenilirdir: yanlış bir profile, patch'lenmiş bir kernel veya saldırgan tarafından manipüle edilmiş structure'lar (Direct Kernel Object Manipulation) reconstruct edilmiş görünümü sessizce bozar.

Walkthrough

Out-of-guest analiz; doğruluk, isabetli symbol'lere bağlıdır

Aşağıdaki konseptler public VMI literatürünü (Garfinkel & Rosenblum; Volatility/LibVMI profile'ları) takip eder. Field offset'leri daima eşleşen bir symbol kaynağından çözülür — asla körü körüne hardcode edilmez.

1. Kernel'e anchor ol. Kernel context'i için guest'in directory base'ini (CR3/KPGD) okuyun ve guest build'i için process-list head symbol'ünü bulun.

2. Process list'ini walk et. Konsept olarak (LibVMI tarzı), head'i translate edin, link'i okuyun ve in-struct offset kadar adımlayın:

// Linux: stride init_task -> task_struct.tasks (list_head) -> name/pid
addr_t list_head = ksym2addr("init_task") + offset("task_struct", "tasks");
addr_t cur = list_head;
do {
    addr_t ts = cur - offset("task_struct", "tasks");      // container_of
    read_str (vmi, ts + offset("task_struct","comm"), name);
    read_u32 (vmi, ts + offset("task_struct","pid"),  &pid);
    read_addr(vmi, cur, &cur);                              // next link
} while (cur != list_head);

Windows eşdeğeri, her EPROCESS'in ActiveProcessLinks field'ı üzerinden PsActiveProcessHead'i walk eder ve ImageFileName ile UniqueProcessId'yi okur.

Reconstruct edilmiş process list (illustrative)
[vmi] CR3=0x1aa000  symbol init_task=0xffffffff8...  off(tasks)=0x...
PID    NAME
1      systemd
412    sshd
1337   suspicious
...reconstructed purely by striding kernel structures in guest RAM...

3. Bir process'in memory'sini oku. Target'ın directory base'ine geçin ve bir guest-virtual address'i bir frame'e çözmek için guest page-table walk'u kendiniz yapın, sonra onu okuyun — "ham RAM"den "şu process'in .text'ine" kadar olan gap'i kapatın.

Detection

  • In-guest: reconstruction RAM'in pasif read'leri'dir, dolayısıyla bir guest genellikle onu doğrudan gözlemleyemez. Ancak enabling mekanizmaları tespit edebilir — örn. state'i tutarlı bir noktada yakalamak için kullanılan EPT trap'leri ya da stepping (bkz. MTF stepping için timing ipuçları).
  • From the host: reconstruction eylemi iyi huylu bir monitoring'dir; host operatörlerinin onun yerine izlediği şey manipülasyon'dur — introspect edilen list ile in-guest enumeration arasındaki discrepancy'ler DKOM tarzı gizlenmeyi açığa çıkarır.

Mitigation

  • Anti-introspection (guest/evasion): reconstruction tam offset'lere bağlı olduğundan, structure-layout randomization, encrypt'li/obfuscate'li kernel object'ler veya DKOM, naif reconstructor'ları kırabilir ya da yanıltabilir.
  • Güvenilir introspection (defender): profile'ları tam guest build'ine sabitleyin (kernel version/symbol hash'leriyle validate edin), birden fazla bağımsız structure'ı cross-check edin (scheduler list vs. handle table vs. page table'lar) ki tek bir tamper'lanmış list false-clean bir görünüm vermesin ve race'leri önlemek için state'i sakinleştirilmiş (quiesced) bir noktada yakalayın.

References