成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

探索Windows 10的CFG機制

安全 網站安全
隨著操作系統開發人員一直在增強漏洞利用的緩解措施,微軟在Windows 10和Windows 8.1 Update 3中默認啟用了一個新的機制。這個技術稱作控制流保護(CFG)。

[[183632]]

0x00 前言

隨著操作系統開發人員一直在增強漏洞利用的緩解措施,微軟在Windows 10和Windows 8.1 Update 3中默認啟用了一個新的機制。這個技術稱作控制流保護(CFG)。

和其他利用緩解措施機制一樣,例如地址空間布局隨機化(ASLR),和數據執行保護(DEP),它使得漏洞利用更加困難。毫無疑問,它將大大改變攻擊者的利用技術。就像ALSR導致了堆噴射技術的出現,和DEP導致了ROP技術的出現。

為了研究這個特別的技術,我使用了Windows 10 技術預覽版(build 6.4.9841)和使用Visual Studio 2015 預覽版編譯的測試程序。因為目前最新版的Windows 10 技術預覽版(build 10.0.9926)有了一點改變,我將指出不同之處。

為了完全實現CFG,編譯器和操作系統都必須支持它。作為系統層面的利用緩解措施,CFG的實現需要聯合編譯器、操作系統用戶層庫和內核模塊。MSDN上面的一篇文章描述了支持CFG開發者需要做的步驟。

微軟的CFG實現主要集中在間接調用保護上。考慮下面測試程序中的代碼:

圖1 - 測試程序的代碼

圖1 - 測試程序的代碼

讓我們看下CFG沒有啟用時的代碼情況。

圖2 - 測試程序的匯編代碼

圖2 - 測試程序的匯編代碼

在上圖中,有一個間接調用。它的目標地址不在編譯時決定,而是在運行時決定。一個利用如下:

圖3 – 怎么濫用間接調用

圖3 – 怎么濫用間接調用

微軟實現的CFG主要關注緩解間接調用和調用不可靠目標的問題(在利用中,這是shellcode的第一步)。

不可靠的目標有明顯特征:在大部分情況下,它不是一個有效的函數起始地址。微軟的CFG實現是基于間接調用的目標必須是一個可靠的函數的起始位置。啟用CFG后的匯編代碼是怎樣的?

圖4 – 啟用CFG后的匯編代碼

圖4 – 啟用CFG后的匯編代碼

在間接調用之前,目標地址傳給_guard_check_icall函數,在其中實現CFG。在沒有CFG支持的Windows中,這個函數不做任何事。在Windows 10中,有了CFG的支持,它指向ntdll!LdrpValidateUserCallTarget函數。這個函數使用目標地址作為參數,并且做了以下事情:

1. 訪問一個bitmap(稱為CFGBitmap),其表示在進程空間內所有函數的起始位置。在進程空間內每8個字節的狀態對應CFGBitmap中的一位。如果在每組8字節中有函數的起始地址,則在CFGBitmap中對應的位設置為1;否則設置為0。下圖是CFGBitmap的一部分示例:

圖5 – CFGBitmap

圖5 – CFGBitmap

2. 將目標地址轉化為CFGBitmap中的一個位。讓我們以00b01030為例:

圖6 – 目標地址

圖6 – 目標地址

高位的3個字節(藍色圈中的24位)是CFGBitmap(單位是4字節/32位)的偏移。在這個例子中,高位的3個字節相當于0xb010。因此,CFGBitmap中指向字節單元的指針是CFGBitmap的基址加上0xb010。

同時,第四位到第八位(紅色圈中的)有值X。如果目標地址以0x10對齊(目標地址&0xf==0),則X為單位內的位偏移值。如果目標地址不以0x10對齊(目標地址&0xf!=0),則X|0x1是位偏移值。

在這個例子中,目標地址是0x00b01030。X的值為6。表達式0x00b01030&0xf值為0;這意味著位偏移也是6。

3. 我們看到第二步定義的位。如果位等于1,意味著間接調用的目標是可靠的,因為它是一個函數的起始地址。如果這個位為0,意味著間接調用的目標是不可靠的,因為它不是一個函數的起始地址。如果間接調用目標是可靠的,函數將不做任何事并且直接執行。如果間接調用是不可靠的,將觸發異常阻止利用代碼運行。

圖7 – CFGBitmap中的值

圖7 – CFGBitmap中的值

值X取自第4位到第8位(上面紅圈中5位)。如果目標地址以0x10對齊(目標地址&0xf==0),X是單元中的位偏移值。如果目標地址不以0x10對齊(目標地址&0xf!=0),X|0x1是位偏移值。在這個例子中,目標地址是0x00b01030,X是6(圖6中紅色圈)。0x00b01030&0xf==0,因此位偏移是6。

在第二步中,位偏移是6。以圖7為例,第6位(紅圈)為1。意味著間接調用的目標是一個可靠的函數地址。

現在,我們已經有了CFG工作機制的基本認識。但是這個技巧帶來了下面的問題:

1. CFGBitmap的位信息來自哪里?

2. 何時且怎么生成CFGBitmap?

3. 系統怎么處理不可靠的間接調用觸發的異常?

0x01 深入CFG實現

我們能在PE文件(啟用CFG的VS2015編譯的)中發現另外的CFG信息。讓我們看下PE文件中的圖1的代碼。這個信息能用VS2015的dumpbin.exe轉儲出來。在PE文件的Load Config Table部分,我們能找到下面的內容:

圖8 – PE信息

圖8 – PE信息

Guard CF address of check-function pointer:_guard_check_icall的地址(見圖4)。在Windows 10預覽版中,當PE文件加載時,_guard_check_icall將被修改并指向nt!LdrpValidateUserCallTarget。

Guard CF function table:函數的相對虛擬地址(RVA)列表的指針,其包含了程序的代碼。每個函數的RVA將轉化為CFGBitmap中的“1”位。換句話說,CFGBitmap的位信息來自Guard CF function table。

Guard CF function count:函數RVA的個數。

CF Instrumented:表明程序中啟用了CFG。

在這里,編譯器完成了CFG的整個工作。剩下的是OS的支持使CFG機制起作用。

1. 在OS引導階段,第一個CFG相關的函數是MiInitializeCfg。這個進程是system。調用堆棧如下:

圖9 – 調用堆棧

圖9 – 調用堆棧

MiInitializeCfg函數的前置工作是創建包含CFGBitmap的共享內存。調用時間可以在NT內核階段1內存管理器初始化時找到(MmInitSystem)。如你所知,在NT內核階段1的初始化期間,它調用MmInitSystem兩次。第一個MmInitSystem將進入MiInitializeCfg。那么MiInitializeCfg做了什么?

圖10 – 函數的主要邏輯

圖10 – 函數的主要邏輯

步驟A:注冊表值來自HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\kernel: MitigationOptions

步驟B:MmEnableCfg是一個全局變量,它被用來表示系統是否啟用CFG功能

步驟C:MiCfgBitMapSection的DesiredAccess允許所有的權限;它的分配類型是“reserve”。在build 10.0.9926和build 6.4.9841中共享內存的大小是不同的。對于build 6.4.9841,它按用戶模式空間大小計算。表達式是size=User Mode Space Size>>6。(>>X:右移X位)。對于build 10.0.9926,這個大小是0x3000000。CFG bitmap能表示整個用戶模式空間。MiCfgBitMapSection是CFG實現的核心組件,因為它被用來包含CFGBitmap。

2. 獲得壓縮RVA列表信息的函數且保存到映像的Control_Area結構。

PE映像第一次加載到系統。NT內核將調用MiRelocateImage來重定位。MiRelocateImage將調用MiParseImageCfgBits。在函數MiParseImageCfgBits中,PE映像的壓縮的RVA列表被計算且存儲在PE映像節中的Control_Area數據結構。在系統引導期間一個PE映像只發生一次。

當PE再次加載進進程,NT內核將調用MiRelocateImageAgain。因為它的壓縮的RVA列表已經保存了(且不需要再次計算),MiRelocateImageAgain不需要調用MiParseImageCfgBits保存一些進程的時間。MiParseImageCfgBits被用來計算壓縮的RVA列表以便在小的空間中保存RVA列表。微軟實現CFG有時間和空間的消耗。在MiRelocateImage中,它的CFG相關的部分被如下描述:

MiParseImageCfgBits被用來計算啟用CFG編譯的模塊的壓縮的RVA列表。在深入這個函數之前,我們將看一下這個函數調用的上下文。函數MiParseImageCfgBits將在MiRelocateImage函數中調用。

函數MiParseImageCfgBits有5個參數:

a) 映像節的Control_Area結構的指針

b) 映像文件內容的指針

c) 映像大小

d) 包含PE可選頭結構的指針

e) 輸出壓縮的CFG函數RVA列表的指針

MiParseImageCfgBits的主要工作如下:

a) 從映像的Load Config Table獲得函數RVA列表

b) 使用壓縮算法壓縮列表,以便在小空間保存列表

c) 創建壓縮的RVA列表作為輸出

3. 在CFGBitmap共享內存對象被創建后,CFGBimap共享內存對象被映射來作為兩種用途:

a) 用來寫共享模塊(.DLL文件等)的bits。這個映射是臨時的;在bits寫入完成后,映射將釋放。通過這個映射寫入的bits信息是共享的,意味著它能被操作系統內所有的進程讀取。這個映射發生在MiUpdateCfgSystemWideBitmap函數中。調用堆棧如下:

圖11 – 調用堆棧

圖11 – 調用堆棧

b) 用來寫私有的bits和讀取校驗間接調用的bits。通過這個映射寫入的bits是私有的,意味著它只能被當前進程讀取。這個映射的生存周期與進程的生命周期相同。這個映射發生子MiCfgInitializeProcess中,調用堆棧如下:

圖12 – 調用堆棧

圖12 – 調用堆棧

基于調用堆棧,我們知道它在一個正在初始化的進程中被映射。Build 10.0.9926和6.4.9841的映射大小是不一樣的。對于6.4.9841,大小是基于用戶模式空間大小計算的。表達式為size=User Mode Sapce Size>>6(>>X:右移X位)。對于10.0.9926,這個大小是0x3000000。映射的空間在進程生命周期內總是存在的。映射的基址和長度將被保存在類型為MI_CFG_BITMAP_INFO的結構體中,且地址被修改了(在6.4.9841中,基址是0xC0802144。在10.0.9926中,是0xC080214C)。我稍后將討論怎么將私有的bits寫入映射空間中。MI_CFG_BITMAP_INFO的結構如下:

4. 一旦PE映像的RVA列表準備好了且CFGBitmap節也映射了,就可以將RVA列表翻譯為CFGBitmap中的bits。

圖13 – 更新CFGBitmap的bits

圖13 – 更新CFGBitmap的bits

在幾種不同的場景下這個過程不太一樣:

在ReloadImage/ReloadImageAgain,通過 MiUpdateCfgSystemWideBitmap寫入共享模塊(如dll)的bits

在進程初始化階段寫入私有模塊(如exe)的bits

寫入VM(虛擬內存)操作的bits

寫入映像和數據段的映射的bits

在深入每個場景之前,我們需要搞清楚一些背景信息。在每個進程中,包含CFGBitmap的空間被分為兩部分:共享和私有。

MiCfgBitMapSection是一個共享內存對象,包含了CFGBitmap的共享的bitmap的內容。它與每個進程共享。當它在自己的虛擬內存空間中映射MiCfgBitMapSection時,每個進程看見的內容都相同。共享模塊(dll等)的bitmap信息將通過3.a節描述的映射方法寫入。

然而每個進程需要CFGBitmap的一部分不是被所有進程共享的。它需要私有寫入一些模塊的bitmap信息到CFGBitmap中。這個私有的部分將不和所有的進程共享。EXE模塊的bitmap信息使用3.b節描述的方法寫入。下圖描述了一個通用的場景。

圖14 – 在MiCfgBitMapSection中的共享部分的bitmap內容的3中過程和他們的私有節

圖14 – 在MiCfgBitMapSection中的共享部分的bitmap內容的3中過程和他們的私有節

a) 在ReloadImage/ReloadImageAgain中,通過MiUpdateCfgSystemWideBitmap寫入共享模塊(dll等)的bits。

如第2節所見,在得到壓縮的函數的RVA列表并將它保存到Control_Area結構后(在build6.4.9841中: _Control_Area ->SeImageStub->[+4]->[+24h];在build10.0.9926中: _Control_Area ->SeImageStub->[+0]->[+24h]),它將調用MiSelectImageBase。這個函數是ASLR實現的核心。它返回最終選擇的基址。選擇的基地址對于寫bit信息到CFGBitmap中非常重要。在得到基地址后,它將調用MiUpdateCfgSystemWideBitmap。

MiUpdateCfgSystemWideBitmap的主要任務是將壓縮的RVA列表翻譯為CFGBitmap中的“1”bit。通過這個函數寫入的bitmap信息是共享的,且被操作系統所有的進程共享。這個函數只針對共享模塊有效(dll文件等)。

MiUpdateCfgSystemWideBitmap有3個參數:

指向Control_Area結構的指針

映像的基址

指向壓縮的RVA列表的指針

MiUpdateCfgSystemWideBitmap的主要邏輯如下:

圖15 – MiUpdateCfgSystemWideBitmap的主要邏輯

圖15 – MiUpdateCfgSystemWideBitmap的主要邏輯

在步驟B中,它映射CFGBitmap共享內存到系統進程空間中。它不映射所有共享內存的全部大小。它轉化映像的基址為CFGBitmap的偏移,且使用轉化的結果作為映射的起始地址。轉為過程如下:

Bitmap的偏移=基地址>>6。按這個公式,映射大小是映像大小右移6位。這個方法在映像需要重定位(ReloadImageAgain函數)的時候也會被使用。

b) 在進程初始化階段寫私有模塊(exe文件等)的bits。它將調用MiCommitVadCfgBits,其是一個派遣函數。你能使用圖13作為參考。它在確定的場景被調用。這個函數的前置工作是在VAD描述的空間寫入bits。主要邏輯如下:

圖16 – MiMarkPrivateImageCfgBits函數處理寫入私有模塊的bits

圖16 – MiMarkPrivateImageCfgBits函數處理寫入私有模塊的bits

MiMarkPrivateImageCfgBits函數實現向CFG Bitmap中寫入私有模塊(exe等)的bit信息。當系統映射一個EXE的節或者啟動一個進程時,這個函數被調用。

這個函數有2個參數:

1) Cfg信息的全局變量地址

2) 映像空間的VAD

VAD是用來描述虛擬內存空間范圍的一個結構。

函數的前置工作是將輸入的VAD的相關的壓縮的RVA列表轉化為bitmap信息,且在CFGBitmap中寫入bits。主要邏輯如下:

圖17 – MiMarkPrivateImageCfgBits的主要邏輯

圖17 – MiMarkPrivateImageCfgBits的主要邏輯

在步驟A中,壓縮的RVA列表能從輸入的VAD關聯的Control_Area結構中獲得,在MiRelocateImage中保存(參見第二節)。

這個函數的主要步驟是步驟C。它實現私有寫入映射的MiCfgBitMapSection32節(在3.b節有描述)。寫入的私有的bits的映射是只讀的。向映射的空間寫入bits怎么實現?關鍵步驟如下:

i. 獲得映射的空間地址的物理地址(PFN)

ii. 申請一個空的頁表入口(PTE)并使用上步獲得的物理地址填充PTE,新的PTE被映射到相同的物理頁,其包含了映射的MiCfgBitMapSection32的虛擬地址。

iii. 復制結果緩沖區(圖12)到新的PTE。物理頁將包含結果緩沖區的內容

iv. 釋放新的PTE

在上面步驟完成后,bitmap信息被拷貝到當前進程地址空間內。但是不會影響MiCfgBitMapSection。換句話說,MiCfgBitMapSection不知道bitmap改變了。其他進程也不會看到改變;新添加的bitmap信息對當前進程是私有的。

c) 寫虛擬內存操作的bits。如果一個進程有虛擬內存操作,它可能會影響CFGBitmap中的bitmap的bits狀態。從圖13的場景看,它將調用MiMarkPrivateImageCfgBits。函數的前置工作是復制“1”或“0”頁到CFGBitmap空間中。

i. 對于NtAllocVirtualMemory函數

如果一個進程調用NtAllocVirtualMemory函數來分配具有可執行屬性的虛擬內存,NT內核將設置CFGBitmap中相關的位為“1”。但是如果分配的內存的保護屬性有 SEC_WRITECOMBINE,NT內核將使用“0”設置bitmap。

ii. 對于MiProtectVirtualMemory函數

如果一個進程調用MiProtectVirtualMemory來改變虛擬內存的保護屬性為“可執行”,NT內核將設置CFGBitmap相關位為“1”。

d) 寫映像和數據段映射的bits

i. 對于映像(dll,EXE等)節的映射,如果映像不是共享的,處理過長如4.b節描述。如果是共享的,將由圖13中的MiMarkPrivateImageCfgBits函數處理。它遍歷映射空間中的每個頁且將頁地址轉化為CFGBitmap中的偏移。

i. 如果CFGBitmap中的偏移不被PrototypePTE支持,相關的bits信息將被拷貝到CFGBitmap空間中。

ii. 如果CFGBitmap中的偏移已經有bitmap信息,CFGBitmap部分將改為只讀。

ii. 對于數據段的映射,處理與4.c.i相同。

5. 上面提到的步驟都發生在內核模式下。但是對于用戶模式,CFGBitmap需要訪問LdrpValidateUserCallTarget函數,它在上一部分已經描述了。用戶模式下怎么知道CFGBitmap映射的地址?當創建一個進程,NT內核調用PspPrepareSystemDllInitBlock函數來寫CFGBitmap映射的地址和全局變量的長度,其數據結構是PspSystemDllInitBlock結構。PspSystemDllInitBlock是修正過的地址并且從用戶模式和內核模式都能訪問。

圖18 – 調用堆棧

圖18 – 調用堆棧

用戶模式可以訪問硬編碼的PspSystemDllInitBlock全局變量的CFGBitmap字段。

6. 在圖4中,_guard_check_icall函數指針將指向ntdll的LdrpValidateUserCallTarget。何時發生,如何發生?LdrpCfgProcessLoadConfig來完成這個工作。進程創建過程將在用戶模式下調用LdrpCfgProcessLoadConfig。

圖19 – 在這個函數中,它將修改_guard_check_icall的值指向LdrpValidateUserCallTarget

圖19 – 在這個函數中,它將修改_guard_check_icall的值指向LdrpValidateUserCallTarget

7. 在所有的準備都完成后,如果間接調用的目標地址相關的位在CFGBitmap中不是“1”,將觸發CFG。進程將采取行動處理這個異常。處理函數是RtlpHandleInvalidUserCallTarget。這個函數使用間接調用的目標為唯一的參數。函數的主要邏輯如下:

圖20 – RtlpHandleInvalidUserCallTarget的主要邏輯

圖20 – RtlpHandleInvalidUserCallTarget的主要邏輯

函數的主要流程是校驗DEP狀態和觸發int 29中斷,這個內核中斷處理例程是KiRaiseSecurityCheckFailure。它的行為是結束進程。

如果一個間接調用的目標地址的CFGBitmap中的相關的位不能訪問(如超出了CFGBitmap空間),意味著目標地址是不可靠的。系統將拋出訪問異常。當這個異常回到用戶模式的處理函數KiUserExceptionDispatcher時,它將調用RTLDispatchException。在RTLDispatchException中,它將校驗異常發生的地址。如果指令的地址能訪問CFGBitmap,它將繼續調用RtlpHandleInvalidUserCallTarget。

8. 如果一個進程需要自定義CFGBitmap,它能調用ntdll中的NtSetInformationVirtualMemory。在內核中函數MiCfgMarkValidEntries實現了這個功能。MiCfgMarkValidEntries以一個緩沖區和長度作為參數。緩沖區中的每個單位是8字節。頭四個字節是目標地址,其想在CFGBitmap中設置相關的位,且后四個字節是設置“0”或“1”的標志。MiCfgMarkValidEntries自定義的CFGBitmap只在當前進程能看見。

9. 如果一個攻擊者需要改變用戶模式下的CFGBitmap的內容,是不可能的。因為CFGBitmap被映射為只讀(在3.b節討論過)。不管改內存保護屬性還是向空間中寫值都將失敗。

0x02 CFG的弱點

當然,這個機制不是沒有弱點的。我們指出了一些弱點如下:

CFGBitmap空間地址存儲在修正過的地址中,其能被用戶模式代碼獲得。這在CFG實現中討論過。這是很重要的安全問題,但是被簡單的放過了。

如果主模塊沒有開啟CFG,即使加載的啟用了CFG的模塊,進程也不會受保護。

基于圖20,如果一個進程的主模塊禁用了DEP(通過/NXCOMPAT:NO),能繞過CFG訪問處理,即使間接調用的目標地址是不可靠的。

在CFGBitmap中的每個bit在進程空間中表示8個字節。因此如果一個不可靠的目標地址少于8個字節,CFG將認為是可靠的。

如果目標函數是動態生成的(類似JIT技術),CFG的實現不能保護。這是因為NtAllocVirtualMemory將在CFGBitmap中為所有分配的可執行的內存空間設置為“1”(4.c.i描述)。通過MiCfgMarkValidEntries自定義的CFGBitmap解決這個問題是可能的。

責任編輯:武曉燕 來源: sjc1-te-ftp.trendmicro
相關推薦

2017-01-20 14:49:46

2009-07-03 18:59:02

2020-09-25 10:14:54

漏洞

2015-09-28 14:12:36

2014-03-04 15:28:32

iOS開發消息傳遞機制

2023-05-09 08:36:58

DuchesneWindows

2023-01-03 14:59:59

Windows 10

2024-09-04 09:47:21

2020-11-01 20:30:53

Windows 10Windows 7Windows

2012-05-02 14:54:21

Windows

2023-09-08 08:01:40

Gateway測試配置

2023-11-08 09:49:19

Java實踐

2009-11-10 09:00:50

2024-06-04 15:56:48

Task?.NET異步編程

2025-01-07 08:00:00

有序集合數據結構

2015-01-06 10:00:00

Windows 10

2016-01-08 10:06:52

2020-10-09 14:57:37

Windows 10Windows微軟

2017-10-24 09:47:57

Windows

2021-01-31 07:50:08

Windows10操作系統Windows 10X
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美日韩中文字幕在线 | 欧美男人天堂 | 成年人在线观看视频 | 亚洲成人久久久 | 欧美一区二区在线视频 | 久久精品国产v日韩v亚洲 | 午夜视频在线 | 亚洲成人网在线观看 | 免费一级毛片 | av激情在线 | 成在线人视频免费视频 | 特级丰满少妇一级aaaa爱毛片 | 一级毛片免费完整视频 | 欧美午夜在线 | 一级在线观看 | 欧美日韩精品久久久免费观看 | 黑人性hd | 黄网免费 | 91av在线看| 中文字幕综合在线 | 欧美一区二区大片 | 欧美日韩在线一区二区三区 | 日本一级淫片免费啪啪3 | 中文字幕乱码视频32 | 91啪影院 | 国产一区二区三区免费观看在线 | 中文字幕免费在线 | 国产小u女发育末成年 | 国产不卡在线 | 久草新视频 | 国产精品久久av | 在线播放国产一区二区三区 | 色妹子综合网 | 一区二区三区四区在线视频 | 玩丰满女领导对白露脸hd | 欧美精品v国产精品v日韩精品 | 欧美精品一区二区在线观看 | 欧美国产视频 | 欧美日韩精品中文字幕 | 午夜成人免费视频 | 亚洲精品永久免费 |