基于虛擬化的安全(part1):引導(dǎo)過程
一、前言
本文是覆蓋基于虛擬化的安全和設(shè)備保護功能的文章的一部分。這些文章的目的是從技術(shù)的角度分享這些功能以便更好的理解。這第一篇文章將涵蓋系統(tǒng)引導(dǎo)過程,從Windows bootloader到VTL0啟動。
二、基于虛擬化的安全
基于虛擬化的安全(VBS)是微軟Windows10和Windows Server2016的一個主要的安全特性。例如,DeviceGuard和CredentialGuard都依賴它。DeviceGuard允許系統(tǒng)阻止任何不受信任的程序。同時CredentialGuard允許系統(tǒng)隔離lsass.exe進程,以便阻止類似Mimikatz等工具內(nèi)存讀取密碼。
這個新功能的主要思想是使用硬件虛擬化技術(shù)(例如Intel VT-x),以便在兩個虛擬機(VM)之間實現(xiàn)強隔離,并且將來功能可能更豐富。這些技術(shù)允許虛擬機管理器(VMM)使用擴展頁表(EPT)來對物理頁設(shè)置不同的權(quán)限。換句話說,一個VM能夠在它的頁表入口(PTE)設(shè)置一個物理頁可寫(+W),并且VMM能夠通過在它的EPT上設(shè)置適當(dāng)?shù)臋?quán)限來授權(quán)或阻止這種行為。
基于虛擬化的安全依賴Hyper-V技術(shù),其將產(chǎn)生不同虛擬信任等級(VTL)的虛擬機。Hyper-V包括一個hypervisor,并且任何操作系統(tǒng),甚至主操作系統(tǒng),都包含在VM中。這個主操作系統(tǒng)(Windows)被認為是根VM。Hyper-V信任它且接受像控制其他VM的管理命令。其他的VM可能是“開明的”,如果這樣,則向Hyper-V發(fā)送受限消息以便他們自己管理。
VTL是有序號的,更高的是最受信任的?,F(xiàn)在有兩個VTL:
1. VTL0,是一個普通的環(huán)境,且基本包含標(biāo)準的Windows操作系統(tǒng)。
2. VTL1,是一個安全的環(huán)境,且包含一個微內(nèi)核和安全的應(yīng)用程序,稱為trustlet。
圖1 – 基于虛擬化的安全的概覽
CredentialGuard安全機制使用這個技術(shù)在VTL1 trustlet(lsaiso.exe,上圖中“Isolated LSA”)中隔離關(guān)鍵的lsass.exe進程,甚至使得VTL0內(nèi)核不能訪問它的內(nèi)存。只有消息可以從VTL0轉(zhuǎn)發(fā)到隔離的進程,有效的阻止了像Mimikatz這類的密碼和哈希收集工具。
DeviceGuard安全機制使得VTL0內(nèi)核地址空間的W^X內(nèi)存緩解(物理頁不能同時具有可執(zhí)行和可寫權(quán)限),并且接受包含授權(quán)代碼簽名者的策略。如果VTL0內(nèi)核想要使一個物理頁可執(zhí)行,它必須請求VTL1來改變(圖中的“HVCI”),它會根據(jù)策略校驗簽名。對于用戶模式的代碼,這不起作用,只有VTL0內(nèi)核才請求簽名驗證。策略在引導(dǎo)啟動時加載,且之后不能修改,只有強制用戶重啟才能加載新的策略。
策略也是被簽名的:在這種情況下,授權(quán)簽名者在UEFI變量中設(shè)置,且新的策略將校驗這個簽名者。UEFI變量設(shè)置他們的Setup和Boot標(biāo)志,意味著在啟動后他們將無法被訪問和修改。為了清除這些變量,本地用戶必須使用一個自定義的微軟EFI bootloader重啟,在用戶交互操作(通過輸入密碼)后移除他們。
因此,VBS強依賴SecureBoot。引導(dǎo)加載器的完整性必須被校驗,因為它負責(zé)加載策略、Hyper-V和VTL1等等。
如果你對設(shè)備保護的細節(jié)感興趣,你能閱讀這個MDSN的文章:https://blogs.technet.microsoft.com/ash/2016/03/02/windows-10-device-guard-and-credential-guard-demystified/。
我們也鼓勵你閱讀Alex lonescu和Rafal Wojtczuk的BlackHat 2015/2016的演講,將有很大幫助:
http://www.alex-ionescu.com/blackhat2015.pdf
https://www.youtube.com/watch?v=LqaWIn4y26E
https://www.blackhat.com/docs/us-16/materials/us-16-Wojtczuk-Analysis-Of-The-Attack-Surface-Of-Windows-10-Virtualization-Based-Security.pdf
https://www.blackhat.com/docs/us-16/materials/us-16-Wojtczuk-Analysis-Of-The-Attack-Surface-Of-Windows-10-Virtualization-Based-Security-wp.pdf
https://www.youtube.com/watch?v=_646Gmr_uo0
本文中,我們將涵蓋系統(tǒng)引導(dǎo)過程,從Windows bootloader到VTL0啟動。為了分析VBS怎么在引導(dǎo)過程期間初始化自身,下面的Windows 10 1607的一些文件已經(jīng)被逆向過了:
- Bootmgr.efi:EFI引導(dǎo)加載器(一小部分)
- Winload.efi:EFI Windows加載器
- Hvix.exe:Hyper-V(相當(dāng)小的一部分)
- Ntoskrnl.exe:NTOS內(nèi)核
- Securekernel.exe:安全內(nèi)核
- Ci.dll:VTL0代碼完整性
- Skci.dll:VTL1代碼完整性
因此讓我們來深入到VBS引導(dǎo)過程中,從winload.efi的執(zhí)行開始,到ntoskrnl.exe的入口點執(zhí)行。
三、引導(dǎo)過程
引導(dǎo)過程可以總結(jié)為5個必須的步驟:
- Bootmgr.efi是第一個加載的組件。由SecureBoot驗證并執(zhí)行
- Bootmgr.efi加載并校驗winload.efi
- Winload加載并校驗VBS配置
- Winload加載并校驗Hyper-V和VTL0/VTL1內(nèi)核組件
- Winload退出EFI模式,啟動Hyper-V
1. Bootmgr.efi
當(dāng)系統(tǒng)開始引導(dǎo),bootmgr.efi是第一個被加載執(zhí)行的。它的完整性和簽名已經(jīng)由Secure Boot UEFI代碼校驗過。為了能夠識別過期的簽名,DBX數(shù)據(jù)庫包含了過期的簽名(截至2016年底,這個數(shù)據(jù)庫包含了71個黑名單和未知的SHA256的哈希值)。在bootmgr.efi的最后,執(zhí)行將轉(zhuǎn)到winload.efi的入口點:OslpMain/OslMain。
OslpMain首先調(diào)用OslpPrepareTarget,其是winload.efi的核心函數(shù)。它將初始化hypervisor,內(nèi)核等。但是先會使用OslSetVsmPolicy初始化VBS配置。
2. VBS策略加載
OslSetVsmPolicy首先校驗VbsPolicyDisabled EFI變量的值(參見下面的微軟命名空間)。如果設(shè)置了,這個變量是0,意味著沒有憑據(jù)保護配置將要加載。這個EFI變量因此將在引導(dǎo)時禁用憑據(jù)保護(并且能夠在VTL0 ring3調(diào)用設(shè)置權(quán)限)。如果沒有設(shè)置,配置將從SYSTEM注冊表的hive中加載,并且由BlVsmSetSystemPolicy調(diào)用執(zhí)行,其將讀取和更新VbsPolicy EFI 變量。相應(yīng)的值被存儲到全局變量BlVsmpSystemPolicy中。如果UEFI鎖開啟,這個EFI變量被設(shè)置,并且不能通過winload.efi禁用(它不能移除它,只能使用自定義的EFI代碼才能)。
函數(shù)OslpPrepareTarget也會調(diào)用OslpProcessSIPolicy(被調(diào)用兩次,第一次直接從函數(shù)OslInitializeCodeIntegrity中調(diào)用)。OslpProcessSIPolicy使用3個EFI變量“pools”來校驗SI策略簽名。每個pool包含3個EFI變量,第一個包含策略,第二個包含版本,第三個包含授權(quán)的策略更新簽名者。例如,對于C:\Windows\System32\CodeIntegrity\SIPolicy.p7b,變量是Si,SiPolicyVersion和SiPolicyUpdateSigners。如果“version”和“update signers”變量被設(shè)置,系統(tǒng)將增強SI策略簽名:它必須是存在且正確的簽名,否則引導(dǎo)將失敗。通過BlSiPolicyIsSignedPolicyRequired函數(shù)來驗證它自己。
3種策略和相關(guān)的變量總結(jié)如下:
我們不確定“revokeSiPolicy”和“skuPolicy”的目的,但是他們似乎和普通的“SiPolicy”使用類似。
3. Hyper-V和內(nèi)核組件的加載
執(zhí)行將轉(zhuǎn)移到OslArchHypervisorSetup函數(shù),其需要使用與執(zhí)行的步驟相應(yīng)的參數(shù)來調(diào)用,從0開始。在第一次,它將初始化Hyper-V(加載hvloader.efi且通過HvlpLaunchHvLoader執(zhí)行它)。SecureBoot設(shè)置通過OslInitializeCodeIntegrity來校驗。
OslpPrepareTarget然后加載NTOS內(nèi)核(ntoskrnl.exe),并且使用OslpLoadAllModules函數(shù)來加載hal.dll和mcupdate.dll模塊。然后“Local Key”和“Identification Key”由OslVsmProvisionLKey和OslVsmProvisionIdk函數(shù)加載。
此時,NTOS內(nèi)核初始化了但還沒喲啟動。以步驟“0”為參數(shù)的OslVsmSetup被調(diào)用(與OslArchHypervisorSetup一樣:以“步驟”為參數(shù)),首先校驗Hyper-V已經(jīng)啟動,然后初始化OslVsmLoaderBlock(參數(shù)在初始化期間由安全內(nèi)核提供)。然后,OslVsmSetup加載安全內(nèi)核(securekernel.exe),并且通過OslpVsmLoadModules函數(shù)加載它依賴的skci.dll(OslLoadImage再次被用來校驗他們的簽名)。EFI變量OslLoaderIndications第一位被設(shè)置為1。
最后,OslVsmSetup函數(shù)再次被調(diào)用,但是參數(shù)是步驟“1”。這個觸發(fā)了OslVsmLoaderBlock的初始化。
當(dāng)函數(shù)OslpPrepareTarget返回后,VBS參數(shù)已經(jīng)被驗證完了,并且NTOS和安全內(nèi)核都被加載了。他們的入口點地址被存儲在全局變量OslpVsmSystemStartup和OslEntryPoint中(securekernel.exe和ntoskrnl.exe)以便將來使用。
四、微軟EFI變量
VBS EFI變量屬于命名空間:{0x77FA9ABD, 0x0359, 0x4D32, 0xBD, 0x60, 0x28, 0xF4, 0xE7, 0x8F, 0x78, 0x4B}。這些變量有他們的“Boot”和“Setup”屬性設(shè)置,因此在EFI引導(dǎo)階段后他們的訪問和修改是不被允許的。
然而轉(zhuǎn)儲他們是可能的,以便在逆向分析中使用。與VBS相關(guān)的EFI變量和他們響應(yīng)的用法總結(jié)如下:
為了轉(zhuǎn)儲這些變量的內(nèi)容,關(guān)閉安全啟動和使用一個簡單的EFI自定義的引導(dǎo)啟動器(gnu-efi和VisualStudio能完美實現(xiàn))。一些變量轉(zhuǎn)儲如下:
五、Hyper-V和安全內(nèi)核啟動
回到OslpPrepareTarget,現(xiàn)在開始執(zhí)行啟動Hyper-V和分割VTL0及VTL1空間。這個過程總結(jié)如下:
Winload在“第一個“Hyper-V VM中運行
Winload調(diào)用安全內(nèi)核的入口點(EP)
securekernel初始化自身,請求Hyper-V內(nèi)存保護
securekernel請求VTL1驗證
Hyper-V啟用VTL1(“第二個“VM),在ShvlpVtlEntry中返回
通過ShvlpVtlReturn,securekernel(現(xiàn)在是VTL1)返回到winload(現(xiàn)在是VTL0)
Winload調(diào)用ntoskrnl入口點
下面是securekernel初始化前后的狀態(tài)(VTL0 VM是藍色塊,VTL1是綠色塊,Hyper-V是橙色塊):
圖2 – securekernel初始化前后的狀態(tài)對比
繼續(xù)執(zhí)行,通過調(diào)用OslFwpKernelSetupPhase1退出EFI模式,并且以“1“參數(shù)調(diào)用OslArchHypervisorSetup啟動Hyper-V。Hvix64通過向HvlpSavedRsp保存的RSP啟動并且將HvlReturnFromHypervisor傳給hvix64。當(dāng)HvlpReturnFromHypervisor被命中,使用cpuid指令來驗證啟動,并且RSP被重置。我們確實處在第一個虛擬機中,其將很快變成VTL1。
OslVsmSetup再次被調(diào)用(step“2”):
- 校驗VBS參數(shù)
- 驗證Hyper-V正確運行
- 修改OslVsmLoaderBlock設(shè)置
- 在相同塊中復(fù)制OslVsmLKeyArray(Local Key)和OslVsmIdk(“Identification Key”)
調(diào)用儲存在OslpVsmSystemStartup中的安全內(nèi)核的入口點,指定OslVsmLoaderBlock和它的大小為參數(shù)。
然后安全內(nèi)核將執(zhí)行它的初始化,并且將調(diào)用SkmiProtectSecureKernelPages以便安裝它自己的內(nèi)存,但是也注冊Hyper-V時間攔截例程(HyperGuard和它的Skpg*前綴的例程)。根據(jù)http://www.sandpile.org/x86/msr.htm,對MSR的操作由SkpgxInterceptMsr攔截處理:
- 0x1B(APIC_BASE)
- 0x1004(?)
- 0x1005(?)
- 0x1006(?)
- 0x100C(?)
- 0xC0000080(EFER)
- 0xC0000081(STAR)
- 0xC0000082(LSTAR)
- 0xC0000083(CSTAR)
- 0xC0000084(FMASK)
- 0xC0000103(TSC_AUX)
- 0x174(SEP_SEL)
- 0x175(SEP_RSP)
- 0x176(SEP_RIP)
- 0x1a0(MISC_ENABLE)
我們的假設(shè)是這個處理器的設(shè)置是為了捕獲VTL0中CPL轉(zhuǎn)變,來阻止關(guān)鍵的MSR修改。還有兩個其他的例程,SkpgxInterceptRegisters和SkpgInterceptRepHypercall。前者可能是攔截CRXXX注冊操作的方法(例如,寫CR4能禁用SMEP),后者是攔截未授權(quán)的調(diào)用(然而這些只是猜測)。
關(guān)于HyperGuard,似乎通過SkpgVerifyExtents執(zhí)行VTL0完整性校驗。SkpgHyperguardRuntime被調(diào)用,可能是計劃執(zhí)行的(使用SkpgSetTimer)。
HyperGuard處理器和回調(diào)函數(shù)被復(fù)制到SkpgContext(由SkpgAllocateContext和SkpgInitializeContext初始化)。
記住上個章節(jié)只是個假設(shè),可能是錯誤的,因為我們現(xiàn)在沒能在VTL1 HyperGuard/PatchGuard例程中花費太多時間。
在初始化的最后,安全內(nèi)核將執(zhí)行兩個調(diào)用:
- 0x0F,ShvlEnableVpVtl,指定一個ShvlpVtl1Entry函數(shù)指針
- 0x12,ShvlpVtlCall,它不會在任何其他地方使用,并且使用它自己的跳板函數(shù)(在下篇文章給出更多細節(jié))。
ShvlpVtl1Entry以SkpPrepareForReturnToNormalMode結(jié)束,并且這個過程會使Hyper-V開啟VTL0和VTL1,回到ShvlpVtl1Entry,再回到winload.efi進入到VTL0的上下文。
最終,當(dāng)回到winload.efi的主函數(shù),將通過OslArchTransferToKernel執(zhí)行NTOS的入口點,它使用OslEntryPoint調(diào)用入口點。
然后執(zhí)行下一個操作,就像Windows在正常環(huán)境中啟動,只是現(xiàn)在NTOS內(nèi)核知道了VBS相關(guān)的組件(如設(shè)備保護)。
六、總結(jié)
基于虛擬化的安全是Windows10安全功能的一個關(guān)鍵組件。通過VBS的安全內(nèi)核的初始化,我們希望這個文章將給想要深入分析這個功能的逆向者幫助。
在第二部分,我們將涵蓋VTL0和VTL1怎么內(nèi)核通信和Hyper-V調(diào)用怎么實現(xiàn)。