JMP trampoline redirection (shadow-page detour)¶
Split bir EPT page'in yalnızca execute (shadow) kopyasına kurulan bir inline-detour hook: function prologue üzerine yazılan bir
JMP, kontrolü hypervisor'ın sağladığı bir handler'a saptırır; handler çalıştıktan sonra orijinal koda geri trampoline yapar — steady state'te exit-free ve guest read'lerine görünmez.
Mechanism¶
Note
Bir int3 hyper-breakpoint'ten (her hit'te bir #BP VM-exit maliyeti
çıkaran) farklı olarak, bir JMP trampoline function prologue içine gerçek bir
control-transfer instruction yazar. Bir EPT split ile patch
yalnızca execute-only shadow frame'de yaşar; read'lere servis edilen clean
frame ise orijinal byte'ları korur (bkz. shadow page mapping).
CPU JMP'yi fetch eder ve saptırır; aynı adrese yapılan guest içi herhangi bir
read ise pristine kodu görür. Redirect sıradan bir execution olduğu için,
split bir kez kurulduktan sonra hit başına VM-exit yoktur — maliyet, hook'un
kendisi değil, split'i koruyan EPT-violation handling'idir.
Detour, yeterince uzağa erişebilen stabil bir reach'e dayanır: x86-64'te relative
bir JMP rel32 ±2 GB kapsar, dolayısıyla engine'ler keyfi bir 64-bit handler'a
ulaşmak için çoğu zaman 14-byte absolute indirect formu kullanır.
Walkthrough¶
Kurulum (secret club introspection write-up'ı; EPT-hook referansları):
- Page'i split et. Hedef function'ı içeren page'i 4 KB granularity'sine böl ve bir shadow frame'e klonla; clean frame'den execute'u kaldır ki fetch'ler trap'lensin ve shadow'a resolve olsun.
- Yalnızca shadow'u patch'le. Prologue'u handler'a giden bir detour ile üzerine yaz. Keyfi bir 64-bit hedef için, register kullanmayan bir absolute jump kullanılır:
; 14-byte absolute indirect jump, no register clobber:
jmp qword ptr [rip+0] ; FF 25 00 00 00 00
dq handler_address ; 8-byte absolute target follows inline
Kaydedilen (üzerine yazılan) orijinal byte'lar, tekrar çalıştırılabilmeleri için saklanır. 3. Handler çalışır ve hypervisor'ın perspektifinden guest state'i gözlemler/değiştirir. 4. Geri trampoline yap. Handler'dan sonra kontrol, relocate edilmiş orijinal prologue byte'larını çalıştıran ve ardından patch'i takip eden instruction'a atlayarak gerçek function'a devam eden ikinci bir JMP üzerinden döner. secret club write-up'ına göre bu yaklaşım "register clobbering'i önler ve breakpoint tabanlı yaklaşımlara kıyasla VM-exit'leri azaltır, orijinal function logic'ine seamless geri dönüş sağlar."
!!! warning Relocate edilen prologue, JMP'nin bir instruction'ı ortadan bölmemesi için length-disassemble edilmelidir ve taşınan byte'lardaki RIP-relative operand'lar fix-up edilmelidir. Detour'dan daha kısa bir prologue'u ya da instruction ortasında bir branch target olan bir prologue'u patch'lemek execution'ı bozar.
Beklenen observable: çalıştırılan prologue bir handler'a giden bir JMP'dir, oysa aynı byte'ların bir read'i (split doğruysa) orijinal prologue'u döndürür; steady-state hit'ler hiçbir VM-exit doğurmaz.
Detection¶
- Bu klasik bir split-view hook olduğundan, hypervisor-assisted hook detection içindeki detector'lar geçerlidir: read/exec divergence (write-to-padding), RDTSC timing ve split'i korumanın EPT-violation overhead'ini açığa çıkaran cross-core thread-race timing'i.
Mitigation¶
- Savunma amaçlı bir monitor için, guest write'larını her iki frame'e de mirror'la ve yukarıdaki detector'lara direnmek için timing'i normalize et (mükemmel stealth garanti değildir).
- Kötü niyetli detour-hooking'i önlemek için, trusted hypervisor EPT/altp2m yapılandırmasının sahibi olmalıdır ki compromise olmuş bir guest bileşeni shadow detour'lar kuramasın; nested kurulumlarda L0, L1 split'lerini sadakatle shadow'lamalıdır.
References¶
- secret club, "Hypervisors for Memory Introspection and Reverse Engineering" (shadow-page detours, 14-byte indirect JMP, split view) — https://secret.club/2025/06/02/hypervisors-for-memory-introspection-and-reverse-engineering.html
- Maurice Heumann (momo5502), "Detecting Hypervisor-assisted Hooking" (split-view hook model + detection) — https://momo5502.com/posts/2022-05-02-detecting-hypervisor-assisted-hooking/