Skip to content

Windows Hardware-enforced Stack Protection

Windows'un Intel CET shadow stack'leri kullanarak backward edge'e her return address'in hardware ile korunan ikinci bir kopyasını vermesi; böylece kaydedilmiş bir return address'i bozan bir stack overwrite, execution'ı yönlendirmek yerine RET anında yakalanır.

Mechanism

Why it works

Control Flow Guard ve XFG yalnızca forward edge'i denetler; klasik ROP ise normal stack üzerindeki return address'leri overwrite ederek çalışır. Hardware-enforced Stack Protection bu boşluğu işlemcinin Intel CET shadow stack'i ile kapatır: return address'lerin, sıradan store'ların yazamadığı, hardware tarafından yönetilen ikinci bir kopyası.

  • Her CALL'da CPU return address'i hem normal stack'e hem de shadow stack'e push eder; RET'te ikisini karşılaştırır. "Anytime a ret instruction happens, a comparison is made between the 'traditional' stack ... and the shadow stack ... If the return address ... doesn't match the shadow stack, we can infer someone corrupted the stack" — yani uyuşmazlık varsa CPU bir control-protection (#CP) fault üretir. CET "provides capabilities to defend against return-oriented programming (ROP) based malware attacks."
  • Bir binary, /CETCOMPAT linker option'ı ile opt-in yapar; bu "tells the linker to mark the binary as CET Shadow Stack-compatible." "Generally, code changes are not needed and the only modification to the binary is a bit in the PE header"; bu switch yalnızca x64'tür ve Visual Studio 2019'dan itibaren kullanılabilir.
  • Enforcement iki modda çalışır. Compatibility mode shadow stack'leri module granularity seviyesinde uygular ve önerilen default'tur, "as third-party DLLs may be injected into your process, and subsequently perform return address hijacking." Strict mode ise "strictly enforces shadow stack protections and will terminate the process if the intended return address is also not on the shadow stack."

Invariant: RET'in güvendiği değer, attacker'ın yazamadığı bir shadow stack'ten alınır, dolayısıyla bozulmuş bir normal-stack return address'i yalnızca fault verebilir, asla control'ü yönlendiremez.

Walkthrough

1. Binary'yi CET-compatible olarak işaretle. Linker switch'ini ekle (x64):

link /CETCOMPAT yourapp.obj

IDE'de: Configuration Properties > Linker > Advanced > CET Shadow Stack Compatible > Yes (/CETCOMPAT).

2. Opt-in bir PE header bit'idir, dolayısıyla mevcut binary'ler source değişikliği olmadan yeniden link edilerek bunu benimseyebilir (shadow stack'i runtime'da loader ile CPU sağlar).

3. Return-address overwrite durumundaki davranış. Kaydedilmiş return address'i yeniden yazan bir stack overflow, shadow kopyayı olduğu gibi bırakır; RET'te ikisi uyuşmaz ve işlemci #CP teslim eder; Windows bunu ROP gadget'ına aktarmak yerine fatal bir exception'a dönüştürür.

Kernel-mode shadow stack'ler (KCET)

Windows, CET shadow stack'leri kernel mode'da da uygular. Kernel CET "REQUIRES that HVCI be enabled," çünkü shadow-stack integrity'sini Secure Kernel (VTL 1) yönetir; her shadow stack'in tepesine yakın bir "restore token" yazılır ve exception'lardan sonra context restore edilirken CPU tarafından doğrulanır; böylece meşru stack switch'leri korunurken corruption fault verir.

Compatibility vs strict

Compatibility mode, inject edilen non-CET DLL'leri tolere etmek için module sınırlarında bilinçli olarak müsamahakârdır; yüklü her module CET-compatible olup strict mode yürürlüğe girene kadar tam garantiyi vermez.

Detection

dumpbin/BinSkim ve process-mitigation sorguları (ProcessUserShadowStackPolicy), shadow stack'lerin etkin olup olmadığını ve hangi modda olduğunu raporlar; bir shadow-stack violation kendini control-protection fast-fail olarak gösterir.

Mitigation

(Residual risk / nasıl bypass edilir.) Shadow stack'ler yalnızca backward edge'i kapsar. Forward-edge hijack'leri — bir indirect CALL/JMP target'ını bozmak, JOP veya counterfeit-object tarzı C++ virtual-call reuse — bunu tamamen bypass eder ve hâlâ CFG/XFG (ve forward edge'de IBT sınıfı tracking) gerektirir. Compatibility mode'un module-granular enforcement'ı, inject edilmiş non-CET DLL'lerin return-address hijacking yapması için bir pencere bırakır; ayrıca hiçbir return address'i bozmayan saf data-only attack'lere dokunulmaz. Bu yapı, CFG, XFG ve kernel CFG ile birlikte katmanlı bir şemanın parçasıdır; hiçbiri tek başına yeterli değildir.

References