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