自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

探索Windows 10的CFG機(jī)制

安全 網(wǎng)站安全
隨著操作系統(tǒng)開發(fā)人員一直在增強(qiáng)漏洞利用的緩解措施,微軟在Windows 10和Windows 8.1 Update 3中默認(rèn)啟用了一個(gè)新的機(jī)制。這個(gè)技術(shù)稱作控制流保護(hù)(CFG)。

[[183632]]

0x00 前言

隨著操作系統(tǒng)開發(fā)人員一直在增強(qiáng)漏洞利用的緩解措施,微軟在Windows 10和Windows 8.1 Update 3中默認(rèn)啟用了一個(gè)新的機(jī)制。這個(gè)技術(shù)稱作控制流保護(hù)(CFG)。

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

為了研究這個(gè)特別的技術(shù),我使用了Windows 10 技術(shù)預(yù)覽版(build 6.4.9841)和使用Visual Studio 2015 預(yù)覽版編譯的測(cè)試程序。因?yàn)槟壳白钚掳娴腤indows 10 技術(shù)預(yù)覽版(build 10.0.9926)有了一點(diǎn)改變,我將指出不同之處。

為了完全實(shí)現(xiàn)CFG,編譯器和操作系統(tǒng)都必須支持它。作為系統(tǒng)層面的利用緩解措施,CFG的實(shí)現(xiàn)需要聯(lián)合編譯器、操作系統(tǒng)用戶層庫和內(nèi)核模塊。MSDN上面的一篇文章描述了支持CFG開發(fā)者需要做的步驟。

微軟的CFG實(shí)現(xiàn)主要集中在間接調(diào)用保護(hù)上??紤]下面測(cè)試程序中的代碼:

圖1 - 測(cè)試程序的代碼

圖1 - 測(cè)試程序的代碼

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

圖2 - 測(cè)試程序的匯編代碼

圖2 - 測(cè)試程序的匯編代碼

在上圖中,有一個(gè)間接調(diào)用。它的目標(biāo)地址不在編譯時(shí)決定,而是在運(yùn)行時(shí)決定。一個(gè)利用如下:

圖3 – 怎么濫用間接調(diào)用

圖3 – 怎么濫用間接調(diào)用

微軟實(shí)現(xiàn)的CFG主要關(guān)注緩解間接調(diào)用和調(diào)用不可靠目標(biāo)的問題(在利用中,這是shellcode的第一步)。

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

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

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

在間接調(diào)用之前,目標(biāo)地址傳給_guard_check_icall函數(shù),在其中實(shí)現(xiàn)CFG。在沒有CFG支持的Windows中,這個(gè)函數(shù)不做任何事。在Windows 10中,有了CFG的支持,它指向ntdll!LdrpValidateUserCallTarget函數(shù)。這個(gè)函數(shù)使用目標(biāo)地址作為參數(shù),并且做了以下事情:

1. 訪問一個(gè)bitmap(稱為CFGBitmap),其表示在進(jìn)程空間內(nèi)所有函數(shù)的起始位置。在進(jìn)程空間內(nèi)每8個(gè)字節(jié)的狀態(tài)對(duì)應(yīng)CFGBitmap中的一位。如果在每組8字節(jié)中有函數(shù)的起始地址,則在CFGBitmap中對(duì)應(yīng)的位設(shè)置為1;否則設(shè)置為0。下圖是CFGBitmap的一部分示例:

圖5 – CFGBitmap

圖5 – CFGBitmap

2. 將目標(biāo)地址轉(zhuǎn)化為CFGBitmap中的一個(gè)位。讓我們以00b01030為例:

圖6 – 目標(biāo)地址

圖6 – 目標(biāo)地址

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

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

在這個(gè)例子中,目標(biāo)地址是0x00b01030。X的值為6。表達(dá)式0x00b01030&0xf值為0;這意味著位偏移也是6。

3. 我們看到第二步定義的位。如果位等于1,意味著間接調(diào)用的目標(biāo)是可靠的,因?yàn)樗且粋€(gè)函數(shù)的起始地址。如果這個(gè)位為0,意味著間接調(diào)用的目標(biāo)是不可靠的,因?yàn)樗皇且粋€(gè)函數(shù)的起始地址。如果間接調(diào)用目標(biāo)是可靠的,函數(shù)將不做任何事并且直接執(zhí)行。如果間接調(diào)用是不可靠的,將觸發(fā)異常阻止利用代碼運(yùn)行。

圖7 – CFGBitmap中的值

圖7 – CFGBitmap中的值

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

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

現(xiàn)在,我們已經(jīng)有了CFG工作機(jī)制的基本認(rèn)識(shí)。但是這個(gè)技巧帶來了下面的問題:

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

2. 何時(shí)且怎么生成CFGBitmap?

3. 系統(tǒng)怎么處理不可靠的間接調(diào)用觸發(fā)的異常?

0x01 深入CFG實(shí)現(xiàn)

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

圖8 – PE信息

圖8 – PE信息

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

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

Guard CF function count:函數(shù)RVA的個(gè)數(shù)。

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

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

1. 在OS引導(dǎo)階段,第一個(gè)CFG相關(guān)的函數(shù)是MiInitializeCfg。這個(gè)進(jìn)程是system。調(diào)用堆棧如下:

圖9 – 調(diào)用堆棧

圖9 – 調(diào)用堆棧

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

圖10 – 函數(shù)的主要邏輯

圖10 – 函數(shù)的主要邏輯

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

步驟B:MmEnableCfg是一個(gè)全局變量,它被用來表示系統(tǒng)是否啟用CFG功能

步驟C:MiCfgBitMapSection的DesiredAccess允許所有的權(quán)限;它的分配類型是“reserve”。在build 10.0.9926和build 6.4.9841中共享內(nèi)存的大小是不同的。對(duì)于build 6.4.9841,它按用戶模式空間大小計(jì)算。表達(dá)式是size=User Mode Space Size>>6。(>>X:右移X位)。對(duì)于build 10.0.9926,這個(gè)大小是0x3000000。CFG bitmap能表示整個(gè)用戶模式空間。MiCfgBitMapSection是CFG實(shí)現(xiàn)的核心組件,因?yàn)樗挥脕戆珻FGBitmap。

2. 獲得壓縮RVA列表信息的函數(shù)且保存到映像的Control_Area結(jié)構(gòu)。

PE映像第一次加載到系統(tǒng)。NT內(nèi)核將調(diào)用MiRelocateImage來重定位。MiRelocateImage將調(diào)用MiParseImageCfgBits。在函數(shù)MiParseImageCfgBits中,PE映像的壓縮的RVA列表被計(jì)算且存儲(chǔ)在PE映像節(jié)中的Control_Area數(shù)據(jù)結(jié)構(gòu)。在系統(tǒng)引導(dǎo)期間一個(gè)PE映像只發(fā)生一次。

當(dāng)PE再次加載進(jìn)進(jìn)程,NT內(nèi)核將調(diào)用MiRelocateImageAgain。因?yàn)樗膲嚎s的RVA列表已經(jīng)保存了(且不需要再次計(jì)算),MiRelocateImageAgain不需要調(diào)用MiParseImageCfgBits保存一些進(jìn)程的時(shí)間。MiParseImageCfgBits被用來計(jì)算壓縮的RVA列表以便在小的空間中保存RVA列表。微軟實(shí)現(xiàn)CFG有時(shí)間和空間的消耗。在MiRelocateImage中,它的CFG相關(guān)的部分被如下描述:

MiParseImageCfgBits被用來計(jì)算啟用CFG編譯的模塊的壓縮的RVA列表。在深入這個(gè)函數(shù)之前,我們將看一下這個(gè)函數(shù)調(diào)用的上下文。函數(shù)MiParseImageCfgBits將在MiRelocateImage函數(shù)中調(diào)用。

函數(shù)MiParseImageCfgBits有5個(gè)參數(shù):

a) 映像節(jié)的Control_Area結(jié)構(gòu)的指針

b) 映像文件內(nèi)容的指針

c) 映像大小

d) 包含PE可選頭結(jié)構(gòu)的指針

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

MiParseImageCfgBits的主要工作如下:

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

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

c) 創(chuàng)建壓縮的RVA列表作為輸出

3. 在CFGBitmap共享內(nèi)存對(duì)象被創(chuàng)建后,CFGBimap共享內(nèi)存對(duì)象被映射來作為兩種用途:

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

圖11 – 調(diào)用堆棧

圖11 – 調(diào)用堆棧

b) 用來寫私有的bits和讀取校驗(yàn)間接調(diào)用的bits。通過這個(gè)映射寫入的bits是私有的,意味著它只能被當(dāng)前進(jìn)程讀取。這個(gè)映射的生存周期與進(jìn)程的生命周期相同。這個(gè)映射發(fā)生子MiCfgInitializeProcess中,調(diào)用堆棧如下:

圖12 – 調(diào)用堆棧

圖12 – 調(diào)用堆棧

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

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

圖13 – 更新CFGBitmap的bits

圖13 – 更新CFGBitmap的bits

在幾種不同的場(chǎng)景下這個(gè)過程不太一樣:

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

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

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

寫入映像和數(shù)據(jù)段的映射的bits

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

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

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

圖14 – 在MiCfgBitMapSection中的共享部分的bitmap內(nèi)容的3中過程和他們的私有節(jié)

圖14 – 在MiCfgBitMapSection中的共享部分的bitmap內(nèi)容的3中過程和他們的私有節(jié)

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

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

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

MiUpdateCfgSystemWideBitmap有3個(gè)參數(shù):

指向Control_Area結(jié)構(gòu)的指針

映像的基址

指向壓縮的RVA列表的指針

MiUpdateCfgSystemWideBitmap的主要邏輯如下:

圖15 – MiUpdateCfgSystemWideBitmap的主要邏輯

圖15 – MiUpdateCfgSystemWideBitmap的主要邏輯

在步驟B中,它映射CFGBitmap共享內(nèi)存到系統(tǒng)進(jìn)程空間中。它不映射所有共享內(nèi)存的全部大小。它轉(zhuǎn)化映像的基址為CFGBitmap的偏移,且使用轉(zhuǎn)化的結(jié)果作為映射的起始地址。轉(zhuǎn)為過程如下:

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

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

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

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

MiMarkPrivateImageCfgBits函數(shù)實(shí)現(xiàn)向CFG Bitmap中寫入私有模塊(exe等)的bit信息。當(dāng)系統(tǒng)映射一個(gè)EXE的節(jié)或者啟動(dòng)一個(gè)進(jìn)程時(shí),這個(gè)函數(shù)被調(diào)用。

這個(gè)函數(shù)有2個(gè)參數(shù):

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

2) 映像空間的VAD

VAD是用來描述虛擬內(nèi)存空間范圍的一個(gè)結(jié)構(gòu)。

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

圖17 – MiMarkPrivateImageCfgBits的主要邏輯

圖17 – MiMarkPrivateImageCfgBits的主要邏輯

在步驟A中,壓縮的RVA列表能從輸入的VAD關(guān)聯(lián)的Control_Area結(jié)構(gòu)中獲得,在MiRelocateImage中保存(參見第二節(jié))。

這個(gè)函數(shù)的主要步驟是步驟C。它實(shí)現(xiàn)私有寫入映射的MiCfgBitMapSection32節(jié)(在3.b節(jié)有描述)。寫入的私有的bits的映射是只讀的。向映射的空間寫入bits怎么實(shí)現(xiàn)?關(guān)鍵步驟如下:

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

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

iii. 復(fù)制結(jié)果緩沖區(qū)(圖12)到新的PTE。物理頁將包含結(jié)果緩沖區(qū)的內(nèi)容

iv. 釋放新的PTE

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

c) 寫虛擬內(nèi)存操作的bits。如果一個(gè)進(jìn)程有虛擬內(nèi)存操作,它可能會(huì)影響CFGBitmap中的bitmap的bits狀態(tài)。從圖13的場(chǎng)景看,它將調(diào)用MiMarkPrivateImageCfgBits。函數(shù)的前置工作是復(fù)制“1”或“0”頁到CFGBitmap空間中。

i. 對(duì)于NtAllocVirtualMemory函數(shù)

如果一個(gè)進(jìn)程調(diào)用NtAllocVirtualMemory函數(shù)來分配具有可執(zhí)行屬性的虛擬內(nèi)存,NT內(nèi)核將設(shè)置CFGBitmap中相關(guān)的位為“1”。但是如果分配的內(nèi)存的保護(hù)屬性有 SEC_WRITECOMBINE,NT內(nèi)核將使用“0”設(shè)置bitmap。

ii. 對(duì)于MiProtectVirtualMemory函數(shù)

如果一個(gè)進(jìn)程調(diào)用MiProtectVirtualMemory來改變虛擬內(nèi)存的保護(hù)屬性為“可執(zhí)行”,NT內(nèi)核將設(shè)置CFGBitmap相關(guān)位為“1”。

d) 寫映像和數(shù)據(jù)段映射的bits

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

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

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

ii. 對(duì)于數(shù)據(jù)段的映射,處理與4.c.i相同。

5. 上面提到的步驟都發(fā)生在內(nèi)核模式下。但是對(duì)于用戶模式,CFGBitmap需要訪問LdrpValidateUserCallTarget函數(shù),它在上一部分已經(jīng)描述了。用戶模式下怎么知道CFGBitmap映射的地址?當(dāng)創(chuàng)建一個(gè)進(jìn)程,NT內(nèi)核調(diào)用PspPrepareSystemDllInitBlock函數(shù)來寫CFGBitmap映射的地址和全局變量的長(zhǎng)度,其數(shù)據(jù)結(jié)構(gòu)是PspSystemDllInitBlock結(jié)構(gòu)。PspSystemDllInitBlock是修正過的地址并且從用戶模式和內(nèi)核模式都能訪問。

圖18 – 調(diào)用堆棧

圖18 – 調(diào)用堆棧

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

6. 在圖4中,_guard_check_icall函數(shù)指針將指向ntdll的LdrpValidateUserCallTarget。何時(shí)發(fā)生,如何發(fā)生?LdrpCfgProcessLoadConfig來完成這個(gè)工作。進(jìn)程創(chuàng)建過程將在用戶模式下調(diào)用LdrpCfgProcessLoadConfig。

圖19 – 在這個(gè)函數(shù)中,它將修改_guard_check_icall的值指向LdrpValidateUserCallTarget

圖19 – 在這個(gè)函數(shù)中,它將修改_guard_check_icall的值指向LdrpValidateUserCallTarget

7. 在所有的準(zhǔn)備都完成后,如果間接調(diào)用的目標(biāo)地址相關(guān)的位在CFGBitmap中不是“1”,將觸發(fā)CFG。進(jìn)程將采取行動(dòng)處理這個(gè)異常。處理函數(shù)是RtlpHandleInvalidUserCallTarget。這個(gè)函數(shù)使用間接調(diào)用的目標(biāo)為唯一的參數(shù)。函數(shù)的主要邏輯如下:

圖20 – RtlpHandleInvalidUserCallTarget的主要邏輯

圖20 – RtlpHandleInvalidUserCallTarget的主要邏輯

函數(shù)的主要流程是校驗(yàn)DEP狀態(tài)和觸發(fā)int 29中斷,這個(gè)內(nèi)核中斷處理例程是KiRaiseSecurityCheckFailure。它的行為是結(jié)束進(jìn)程。

如果一個(gè)間接調(diào)用的目標(biāo)地址的CFGBitmap中的相關(guān)的位不能訪問(如超出了CFGBitmap空間),意味著目標(biāo)地址是不可靠的。系統(tǒng)將拋出訪問異常。當(dāng)這個(gè)異?;氐接脩裟J降奶幚砗瘮?shù)KiUserExceptionDispatcher時(shí),它將調(diào)用RTLDispatchException。在RTLDispatchException中,它將校驗(yàn)異常發(fā)生的地址。如果指令的地址能訪問CFGBitmap,它將繼續(xù)調(diào)用RtlpHandleInvalidUserCallTarget。

8. 如果一個(gè)進(jìn)程需要自定義CFGBitmap,它能調(diào)用ntdll中的NtSetInformationVirtualMemory。在內(nèi)核中函數(shù)MiCfgMarkValidEntries實(shí)現(xiàn)了這個(gè)功能。MiCfgMarkValidEntries以一個(gè)緩沖區(qū)和長(zhǎng)度作為參數(shù)。緩沖區(qū)中的每個(gè)單位是8字節(jié)。頭四個(gè)字節(jié)是目標(biāo)地址,其想在CFGBitmap中設(shè)置相關(guān)的位,且后四個(gè)字節(jié)是設(shè)置“0”或“1”的標(biāo)志。MiCfgMarkValidEntries自定義的CFGBitmap只在當(dāng)前進(jìn)程能看見。

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

0x02 CFG的弱點(diǎn)

當(dāng)然,這個(gè)機(jī)制不是沒有弱點(diǎn)的。我們指出了一些弱點(diǎn)如下:

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

如果主模塊沒有開啟CFG,即使加載的啟用了CFG的模塊,進(jìn)程也不會(huì)受保護(hù)。

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

在CFGBitmap中的每個(gè)bit在進(jìn)程空間中表示8個(gè)字節(jié)。因此如果一個(gè)不可靠的目標(biāo)地址少于8個(gè)字節(jié),CFG將認(rèn)為是可靠的。

如果目標(biāo)函數(shù)是動(dòng)態(tài)生成的(類似JIT技術(shù)),CFG的實(shí)現(xiàn)不能保護(hù)。這是因?yàn)镹tAllocVirtualMemory將在CFGBitmap中為所有分配的可執(zhí)行的內(nèi)存空間設(shè)置為“1”(4.c.i描述)。通過MiCfgMarkValidEntries自定義的CFGBitmap解決這個(gè)問題是可能的。

責(zé)任編輯:武曉燕 來源: sjc1-te-ftp.trendmicro
相關(guān)推薦

2017-01-20 14:49:46

2020-09-25 10:14:54

漏洞

2009-07-03 18:59:02

2015-09-28 14:12:36

2014-03-04 15:28:32

iOS開發(fā)消息傳遞機(jī)制

2024-09-04 09:47:21

2023-05-09 08:36:58

DuchesneWindows

2023-09-08 08:01:40

Gateway測(cè)試配置

2023-11-08 09:49:19

Java實(shí)踐

2023-01-03 14:59:59

Windows 10

2012-05-02 14:54:21

Windows

2020-11-01 20:30:53

Windows 10Windows 7Windows

2024-06-04 15:56:48

Task?.NET異步編程

2025-01-07 08:00:00

有序集合數(shù)據(jù)結(jié)構(gòu)

2016-01-08 10:06:52

2009-11-10 09:00:50

2017-10-24 09:47:57

Windows

2016-12-28 10:34:58

2024-03-27 10:14:48

2015-01-06 10:00:00

Windows 10
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)