一種代碼復(fù)用攻擊的防御方法【專利摘要】本發(fā)明公開(kāi)了一種代碼復(fù)用攻擊的防御方法,包括在庫(kù)文件中增加新段,令所述新段中保存的語(yǔ)句為庫(kù)文件的代碼段的數(shù)據(jù)語(yǔ)句;然后加載所述庫(kù)文件;最后將所述代碼段分別加載至只讀的內(nèi)存頁(yè)以及只執(zhí)行的內(nèi)存頁(yè);通過(guò)所述新段中保存的語(yǔ)句,判斷只讀的內(nèi)存頁(yè)以及只執(zhí)行的內(nèi)存頁(yè)中加載的代碼段中的語(yǔ)句為數(shù)據(jù)語(yǔ)句或者指令語(yǔ)句,并將所述只讀的內(nèi)存頁(yè)中的指令語(yǔ)句以及只執(zhí)行的內(nèi)存頁(yè)中的數(shù)據(jù)語(yǔ)句替換為無(wú)效語(yǔ)句。本發(fā)明通過(guò)以不同的內(nèi)存頁(yè)分別儲(chǔ)存指令語(yǔ)句和數(shù)據(jù)語(yǔ)句,從而防御代碼復(fù)用攻擊,本發(fā)明不依賴于具體的處理器硬件平臺(tái),任何基于windows平臺(tái)的虛擬系統(tǒng)都可以實(shí)施本發(fā)明提出的技術(shù)方案?!緦@f(shuō)明】一種代碼復(fù)用攻擊的防御方法
技術(shù)領(lǐng)域:
[0001]本發(fā)明屬于系統(tǒng)安全
技術(shù)領(lǐng)域:
,更具體地,涉及一種代碼復(fù)用攻擊的防御方法。【
背景技術(shù):
】[0002]代碼復(fù)用攻擊是指在系統(tǒng)共享庫(kù)文件中(動(dòng)態(tài)鏈接庫(kù),如Windows系統(tǒng)SyStem32目錄下的ntdll.dll)或者程序運(yùn)行時(shí)的內(nèi)存空間(內(nèi)核空間、可執(zhí)行進(jìn)程空間等)已有的代碼中搜索可利用的具有特定特征的指令片段(gadgets,通常以ret等匯編指令結(jié)尾),并將其鏈接成可連續(xù)執(zhí)行的指令序列(以ret等匯編指令實(shí)現(xiàn)跳轉(zhuǎn)),再結(jié)合緩沖區(qū)溢出覆蓋函數(shù)的返回地址等技術(shù),使程序轉(zhuǎn)而執(zhí)行構(gòu)造好的指令序列(由gadgets鏈接而成),最終可執(zhí)行系統(tǒng)調(diào)用(如system()函數(shù))獲得系統(tǒng)權(quán)限或調(diào)用系統(tǒng)函數(shù)(如VirtualProtect)修改內(nèi)存屬性(讀、寫(xiě)、執(zhí)行),執(zhí)行預(yù)先構(gòu)造的攻擊程序。[0003]代碼復(fù)用攻擊利用了系統(tǒng)執(zhí)行程序時(shí)的以下幾個(gè)特點(diǎn):(i)程序執(zhí)行時(shí)內(nèi)存中的代碼頁(yè)為可讀和可執(zhí)行權(quán)限(代碼頁(yè)中存在需要讀的數(shù)據(jù)指令在共享庫(kù)文件或內(nèi)存中大量存在;(iii)每個(gè)gadget包含的指令條數(shù)(即由gadgets組成的指令序列中兩個(gè)ret指令之間的指令數(shù)目)很少;(ivket/call指令對(duì)數(shù)目嚴(yán)重失衡(call指令調(diào)用函數(shù),ret指令返回,這兩條指令在大多數(shù)情況下成對(duì)出現(xiàn))。針對(duì)構(gòu)建代碼復(fù)用攻擊的這些特點(diǎn),出現(xiàn)了不少的防御方法。[0004]其中,Hidem方法利用一些早期處理器(CPU)架構(gòu)獨(dú)有的Split-TLB特性(分別通過(guò)不同的高速緩存訪問(wèn)數(shù)據(jù)頁(yè)和代碼頁(yè))將可執(zhí)行的代碼頁(yè)中存在的數(shù)據(jù)和代碼進(jìn)行分離,為程序在內(nèi)存中執(zhí)行時(shí)的每一個(gè)代碼頁(yè)額外分配一個(gè)具有只執(zhí)行權(quán)限的內(nèi)存頁(yè)面,用于保存代碼頁(yè)中的代碼。這樣攻擊者在執(zhí)行程序搜索內(nèi)存空間時(shí)就會(huì)因?yàn)椴荒茏x取代碼頁(yè)中的代碼而無(wú)法構(gòu)造具有攻擊能力的指令序列,從而達(dá)到防御代碼復(fù)用攻擊的目的。但這種方法消耗的內(nèi)存受到執(zhí)行的程序的影響,最高可能達(dá)到程序可執(zhí)行代碼使用內(nèi)存的兩倍,約為2MB~20MB,同時(shí)現(xiàn)有的處理器已經(jīng)沒(méi)有Split-TLB特性,因此Hidem所能防御的平臺(tái)十分有限?!?br/>發(fā)明內(nèi)容】[0005]針對(duì)現(xiàn)有技術(shù)的以上缺陷或改進(jìn)需求,本發(fā)明提供了一種代碼復(fù)用攻擊的防御方法,其目的在于以不同的內(nèi)存頁(yè)分別儲(chǔ)存指令語(yǔ)句和數(shù)據(jù)語(yǔ)句,從而防御代碼復(fù)用攻擊。[0006]為實(shí)現(xiàn)上述目的,按照本發(fā)明的一個(gè)方面,提供了一種代碼復(fù)用攻擊的防御方法,包括以下步驟:[0007]S1.在庫(kù)文件中增加新段,令所述新段中保存的語(yǔ)句為庫(kù)文件的代碼段的數(shù)據(jù)語(yǔ)句;[0008]S2.將所述庫(kù)文件加載至內(nèi)存;[0009]S3.將所述庫(kù)文件的代碼段分別加載至內(nèi)存中只讀的內(nèi)存頁(yè)以及只執(zhí)行的內(nèi)存頁(yè);通過(guò)所述新段中保存的語(yǔ)句,判斷加載后的代碼段中的語(yǔ)句是否為數(shù)據(jù)語(yǔ)句,并將所述只讀的內(nèi)存頁(yè)中的非數(shù)據(jù)語(yǔ)句以及只執(zhí)行的內(nèi)存頁(yè)中的數(shù)據(jù)語(yǔ)句替換為無(wú)效語(yǔ)句。[0010]優(yōu)選地,所述步驟S1具體包括如下子步驟:[0011]S11.將庫(kù)文件的代碼段的數(shù)據(jù)語(yǔ)句儲(chǔ)存于臨時(shí)文件;[0012]S12.在庫(kù)文件中增加新段,并將臨時(shí)文件中儲(chǔ)存的數(shù)據(jù)語(yǔ)句復(fù)制至新段。[0013]作為進(jìn)一步優(yōu)選地,所述步驟S11具體為:根據(jù)庫(kù)文件的代碼段的語(yǔ)句的操作碼是否為空,判斷該語(yǔ)句是否為數(shù)據(jù)語(yǔ)句,是則將該語(yǔ)句儲(chǔ)存入臨時(shí)文件,否則對(duì)該語(yǔ)句不作任何處理。[0014]作為進(jìn)一步優(yōu)選地,所述步驟S12具體為:[0015]將庫(kù)文件的頭部中的段的數(shù)值+1;在庫(kù)文件的boundimport段以及security段之前插入新段,令所述新段中保存的語(yǔ)句為臨時(shí)文件中的數(shù)據(jù)語(yǔ)句;修改庫(kù)文件的頭字節(jié)以及fe驗(yàn)和。[00?6]優(yōu)選地,所述方法用于基于windows平臺(tái)的虛擬系統(tǒng)。[0017]總體而言,通過(guò)本發(fā)明所構(gòu)思的以上技術(shù)方案與現(xiàn)有技術(shù)相比,具有下列有益效果:[0018]1、采用不同的內(nèi)存頁(yè)分別儲(chǔ)存數(shù)據(jù)語(yǔ)句和指令語(yǔ)句,僅需多分配和原有頁(yè)面數(shù)量相同的內(nèi)存頁(yè),經(jīng)驗(yàn)證僅消耗2MB內(nèi)存,優(yōu)于現(xiàn)有技術(shù)中的Hidem方法;[0019]2、不依賴于具體的處理器硬件平臺(tái),任何能夠模擬完整硬件環(huán)境的開(kāi)源虛擬系統(tǒng)的windows平臺(tái)都可以實(shí)施本發(fā)明提出的技術(shù)方案。【附圖說(shuō)明】[0020]圖1為現(xiàn)有技術(shù)和本發(fā)明實(shí)施例1進(jìn)行內(nèi)存訪問(wèn)的示意圖;[0021]圖2為本發(fā)明實(shí)施例1將所述只讀的內(nèi)存頁(yè)中的指令語(yǔ)句以及只執(zhí)行的內(nèi)存頁(yè)中的數(shù)據(jù)語(yǔ)句替換為無(wú)效語(yǔ)句的示意圖;[0022]圖3為本發(fā)明實(shí)施例1的頁(yè)面寫(xiě)回示意圖;[0023]圖4為本發(fā)明實(shí)施例1虛擬多TLB系統(tǒng)處理C0W的過(guò)程。【具體實(shí)施方式】[0024]為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點(diǎn)更加清楚明白,以下結(jié)合附圖及實(shí)施例,對(duì)本發(fā)明進(jìn)行進(jìn)一步詳細(xì)說(shuō)明。應(yīng)當(dāng)理解,此處所描述的具體實(shí)施例僅僅用以解釋本發(fā)明,并不用于限定本發(fā)明。此外,下面所描述的本發(fā)明各個(gè)實(shí)施方式中所涉及到的技術(shù)特征只要彼此之間未構(gòu)成沖突就可以相互組合。[0025]本發(fā)明提供了一種代碼復(fù)用攻擊的防御方法,該方法可用于基于windows平臺(tái)的虛擬系統(tǒng),包括以下步驟:[0026]S1.在庫(kù)文件中增加新段,令所述新段中保存的語(yǔ)句為庫(kù)文件的代碼段的數(shù)據(jù)語(yǔ)句,該步驟又包括如下子步驟:[0027]S11.根據(jù)庫(kù)文件的代碼段中的語(yǔ)句的操作碼是否為空,判斷該語(yǔ)句是否為數(shù)據(jù)語(yǔ)句,是則該語(yǔ)句為數(shù)據(jù)語(yǔ)句,將數(shù)據(jù)語(yǔ)句儲(chǔ)存入臨時(shí)文件;否則該語(yǔ)句為非數(shù)據(jù)語(yǔ)句,即指令語(yǔ)句,不對(duì)該語(yǔ)句作任何處理;[0028]S12.將庫(kù)文件的頭部中的段的數(shù)值+1;在庫(kù)文件的boundimport段以及security段之前插入新段(如果庫(kù)文件既沒(méi)有boundimport段或security段,則可在任意位置插入新段,但為了加載時(shí)的便利,一般將新段插入至除boundimport段以及security段以外其它所有段的尾部),令所述新段中保存的語(yǔ)句為臨時(shí)文件中的數(shù)據(jù)語(yǔ)句;修改庫(kù)文件的頭字節(jié)以及校驗(yàn)和。[0029]S2.將所述庫(kù)文件加載至內(nèi)存;[0030]S3.將所述庫(kù)文件的代碼段分別加載至內(nèi)存中只讀的內(nèi)存頁(yè)以及只執(zhí)行的內(nèi)存頁(yè);通過(guò)步驟S1中的所述新段中保存的語(yǔ)句,判斷加載后的代碼段中的語(yǔ)句是否為數(shù)據(jù)語(yǔ)句,并將所述只讀的內(nèi)存頁(yè)中的非數(shù)據(jù)語(yǔ)句(除了數(shù)據(jù)語(yǔ)句以外的其它語(yǔ)句,即指令語(yǔ)句)以及只執(zhí)行的內(nèi)存頁(yè)中的數(shù)據(jù)語(yǔ)句替換為無(wú)效語(yǔ)句。[0031]實(shí)施例1[0032]本實(shí)施例的目的在于針對(duì)現(xiàn)有Windows系統(tǒng)對(duì)內(nèi)存中代碼段賦予可讀可執(zhí)行權(quán)限的缺點(diǎn),結(jié)合能夠模擬完整硬件環(huán)境的開(kāi)源虛擬機(jī)系統(tǒng)提出了一種代碼復(fù)用攻擊的防御方法,包括以下步驟:[0033]S1.在庫(kù)文件中增加新段,所述新段為數(shù)據(jù)段,在添加后設(shè)置為只讀;將庫(kù)文件的代碼段的數(shù)據(jù)語(yǔ)句保存于新段中;所述代碼段由數(shù)據(jù)語(yǔ)句和指令語(yǔ)句組成;[0034]S11.對(duì)Windows系統(tǒng)庫(kù)文件進(jìn)行靜態(tài)分析,結(jié)合IDAPro用python語(yǔ)言編寫(xiě)插件采用遞歸下降反匯編算法識(shí)別庫(kù)文件的代碼段中的數(shù)據(jù)語(yǔ)句。首先,獲得庫(kù)文件預(yù)設(shè)的加載基址及庫(kù)文件中包含的段數(shù)目;接著,遍歷其中的所有段以獲得代碼段的起始地址和結(jié)束地址;然后,依次分析代碼段中的每一條語(yǔ)句,根據(jù)語(yǔ)句的操作碼是否為空來(lái)判斷該條語(yǔ)句為指令語(yǔ)句或數(shù)據(jù)語(yǔ)句;如該語(yǔ)句為數(shù)據(jù)語(yǔ)句,則將此數(shù)據(jù)語(yǔ)句的首地址和尾地址以相對(duì)偏移的形式寫(xiě)入臨時(shí)文件,直至代碼段中所有的數(shù)據(jù)語(yǔ)句均寫(xiě)入臨時(shí)文件;[0035]S12.由于Windows系統(tǒng)提供了成百上千的動(dòng)態(tài)鏈接庫(kù),如果將從庫(kù)文件的代碼段提取到臨時(shí)文件的數(shù)據(jù)語(yǔ)句保存到額外的文件,那么加載器在加載庫(kù)文件的同時(shí)必須加載保存了數(shù)據(jù)語(yǔ)句的文件,這樣會(huì)加重加載器的負(fù)擔(dān)。為了解決這一問(wèn)題,本發(fā)明在庫(kù)文件的尾部插入一新段,并設(shè)置為只讀,用于保存臨時(shí)文件中的數(shù)據(jù)語(yǔ)句,并給該新段命名為".0(^3"。具體操作如下:[0036]S121.獲取庫(kù)文件的頭部(IMAGE_NT_HEADER)的偏移量,根據(jù)獲得的偏移量將庫(kù)文件的頭部中的段的數(shù)值+1;并在最后一個(gè)段的結(jié)束位置處插入新段(即.cdata段);如果庫(kù)文件中包含邊界導(dǎo)入(boundimport)段或安全(security)段,則將其依次移至.cdata段之后,否則不做移動(dòng);[0037]S122.將庫(kù)文件的頭字節(jié)修改為原庫(kù)文件的大小+新段的大小;[0038]S123.獲得庫(kù)文件的校驗(yàn)和,并將其保存;[0039]得到包含.cdata段的庫(kù)文件之后,用該文件去覆蓋Windows系統(tǒng)原有的庫(kù)文件。我們的Windows系統(tǒng)是QHMU虛擬機(jī)生成的系統(tǒng)鏡像,其本質(zhì)是可掛載文件系統(tǒng),因此,掛載之后便可直接進(jìn)行替換。這樣,系統(tǒng)加載的庫(kù)文件都包含.cdata段。[0040]S2.將所述庫(kù)文件加載至內(nèi)存;[0041]S21.本實(shí)施例所用的QEMU虛擬系統(tǒng)的VMI接口中包含表示系統(tǒng)運(yùn)行時(shí)狀態(tài)的兩個(gè)重要數(shù)據(jù)結(jié)構(gòu):加載模塊(classmodule)以及運(yùn)行進(jìn)程(classprocess)。[0042]在表示加載模塊(classmodule)以及表示運(yùn)行進(jìn)程(classprocess)的類結(jié)構(gòu)中新增成員變量,用于保存庫(kù)文件的新段的信息,具體描述如表1和表2所示:[0043]表lclassmodule新增的成員變量[0044][0045]表2classprocess新增的成員變量[0046][0047]S22.通過(guò)步驟S1,我們已經(jīng)將數(shù)據(jù)語(yǔ)句保存在庫(kù)文件的.cdata段中,由于classmodule是對(duì)庫(kù)文件(如exe、dll等)加載到內(nèi)存之后的抽象,因此必須將.cdata段從庫(kù)文件中提取出來(lái)并保存到classmodule中。當(dāng)然,一個(gè)module不是獨(dú)立存在的,它必然關(guān)聯(lián)于某一個(gè)process。所以,通過(guò)檢測(cè)module的加載,便可以將module所表示的庫(kù)文件的新段中的數(shù)據(jù)語(yǔ)句成功"轉(zhuǎn)移"至內(nèi)存。先判斷正在加載的庫(kù)文件是否含有.cdata段,如果沒(méi)有則直接返回;如果有則遍歷.cdata段,提取所有的數(shù)據(jù)語(yǔ)句,并將它們分別保存到模塊結(jié)構(gòu)(module)和進(jìn)程結(jié)構(gòu)(process)中,同時(shí)設(shè)置相關(guān)變量。[0048]S3.到目前為止,運(yùn)行進(jìn)程鏈接的庫(kù)文件中代碼段的數(shù)據(jù)語(yǔ)句已經(jīng)全部轉(zhuǎn)移至內(nèi)存了。但是,進(jìn)程結(jié)構(gòu)所表示的內(nèi)存中的內(nèi)存頁(yè)不僅包含代碼頁(yè)還包含數(shù)據(jù)頁(yè)等非代碼頁(yè),而且不是每一個(gè)代碼頁(yè)都包含非執(zhí)行數(shù)據(jù)。[0049]因此,在系統(tǒng)執(zhí)行缺頁(yè)中斷程序后得到一個(gè)要訪問(wèn)頁(yè)面(頁(yè)面的地址可以是正在執(zhí)行程序內(nèi)存空間內(nèi)的任何地址值)的地址時(shí),準(zhǔn)確并迅速的給出其包含的數(shù)據(jù)區(qū)間至關(guān)重要。首先由系統(tǒng)上下文結(jié)構(gòu)的cr[3]成員得到頁(yè)表基地址;再結(jié)合進(jìn)程中保存的數(shù)據(jù)區(qū)間判斷正在加載的內(nèi)存頁(yè)中是否包含這些數(shù)據(jù)區(qū)間值;如果包含,就將屬于此頁(yè)面的數(shù)據(jù)區(qū)間信息保存到臨時(shí)數(shù)組中供后面的頁(yè)面覆蓋時(shí)使用。[0050]本實(shí)施例所用的QEMU虛擬系統(tǒng)的軟件內(nèi)存管理(SoftwareMemoryManageUnit,SoftMMU)單元為提高系統(tǒng)運(yùn)行速度,引入快表(TranslationLookasideBuffer,TLB)的設(shè)計(jì)思想。通過(guò)TLB實(shí)現(xiàn)客戶機(jī)(運(yùn)行在虛擬機(jī)上的系統(tǒng))虛擬地址和主機(jī)(運(yùn)行虛擬機(jī)的系統(tǒng))虛擬地址之間的映射。為了實(shí)現(xiàn)代碼段中代碼和數(shù)據(jù)的分離,本發(fā)明在原有TLB的基礎(chǔ)上實(shí)現(xiàn)了虛擬多TLB,即新增一個(gè)和TLB具有相似結(jié)構(gòu)的快表--DTLB?;舅枷胧峭ㄟ^(guò)TLB訪問(wèn)數(shù)據(jù)語(yǔ)句所在頁(yè)面(即只讀的內(nèi)存頁(yè)的區(qū)域),讓DTLB指向指令語(yǔ)句所在的只執(zhí)行的內(nèi)存頁(yè)的區(qū)域。TLB所指的頁(yè)面為原頁(yè)面(即只讀的內(nèi)存頁(yè)),而DTLB所指的頁(yè)面為拷貝頁(yè)面(即只執(zhí)行的內(nèi)存頁(yè))。圖la和b分別描述了現(xiàn)有虛擬機(jī)只利用TLB訪問(wèn)內(nèi)存(原有TLB機(jī)制)和虛擬多TLB機(jī)制進(jìn)行內(nèi)存訪問(wèn)的示意圖。[0051]在原有TLB機(jī)制下,系統(tǒng)無(wú)論是執(zhí)行操作還是讀操作,都是通過(guò)TLB訪問(wèn)相同的內(nèi)存頁(yè)面。而本實(shí)施例令TLB指向的原頁(yè)面只保存代碼頁(yè)中的數(shù)據(jù)語(yǔ)句,其指令語(yǔ)句被"挖除"(即被無(wú)效語(yǔ)句所替換);DTLB指向的拷貝頁(yè)面只保存代碼頁(yè)中的代碼語(yǔ)句,其數(shù)據(jù)語(yǔ)句也被"挖除"(即被無(wú)效語(yǔ)句所替換),如圖2所示。當(dāng)操作系統(tǒng)發(fā)出讀的信號(hào)時(shí),CPU將通過(guò)TLB獲得不包含代碼語(yǔ)句的原頁(yè)面的內(nèi)存地址;若操作系統(tǒng)發(fā)出的是執(zhí)行的信號(hào),CPU將通過(guò)DTLB獲得只包含代碼語(yǔ)句的拷貝頁(yè)面的內(nèi)存地址。[0052]Qemu的TLB是一個(gè)2*256的二維數(shù)組,它是通過(guò)宏定義實(shí)現(xiàn)的。Qemu中的TLB實(shí)質(zhì)是CF^JTLBEntry數(shù)組,它的前三個(gè)成員addr_read、addr_write和addr_code均為內(nèi)存虛擬地址,分別表示讀、寫(xiě)和執(zhí)行地址;將虛擬地址加上addend便得到物理地址。[0053]由于虛擬多TLB(即TLB和DTLB)指向進(jìn)程空間中的同一頁(yè)面,因此DTLB和TLB可以共用TLB中的前面三個(gè)變量。也就是說(shuō),DTLB只需要一個(gè)成員addend。[0054]S31.將代碼段儲(chǔ)存入TLB所指的頁(yè)面即原頁(yè)面,所述原頁(yè)面為只讀的內(nèi)存頁(yè),并將DTLB所指的頁(yè)面對(duì)原頁(yè)面進(jìn)行復(fù)制獲得拷貝頁(yè)面,所述拷貝頁(yè)面為只執(zhí)行的內(nèi)存頁(yè);[0055]S32.通過(guò)庫(kù)文件的新段中保存的數(shù)據(jù)語(yǔ)句,判斷原頁(yè)面以及拷貝頁(yè)面中儲(chǔ)存的代碼段中的語(yǔ)句為數(shù)據(jù)語(yǔ)句還是指令語(yǔ)句,與庫(kù)文件的新段中保存的數(shù)據(jù)語(yǔ)句相同則為數(shù)據(jù)語(yǔ)句,否則為指令語(yǔ)句;并將原頁(yè)面中的指令語(yǔ)句以及拷貝頁(yè)面中的數(shù)據(jù)語(yǔ)句替換為無(wú)效語(yǔ)句。[0056]在QEMU虛擬系統(tǒng)中,內(nèi)存頁(yè)面調(diào)入內(nèi)存時(shí),先由底層硬件完成內(nèi)容的拷貝,然后通過(guò)tlb_set_page()函數(shù)完成TLB的填充。因此,我們只需要在tlb_set_page()函數(shù)中合適的地方調(diào)用mtlb_cover_dtlb_page()函數(shù)便將調(diào)入的內(nèi)存頁(yè)中的指令語(yǔ)句以及拷貝頁(yè)中的數(shù)據(jù)語(yǔ)句替換為無(wú)效語(yǔ)句,在本實(shí)施例中采用了0xF4作為無(wú)效語(yǔ)句。[0057]內(nèi)存頁(yè)面回寫(xiě)[0058]在程序運(yùn)行時(shí),通過(guò)頁(yè)表將虛擬地址映射到物理內(nèi)存。每個(gè)進(jìn)程有屬于自己的頁(yè)表,但所有進(jìn)程共用TLB,即TLB具有唯一性。顯然在進(jìn)程切換時(shí),由于虛擬進(jìn)程空間發(fā)生了變化,會(huì)刷新TLB,有時(shí)會(huì)將舊進(jìn)程在內(nèi)存中的部分頁(yè)面置換出內(nèi)存。我們暫時(shí)將這種由于進(jìn)程切換等原因而導(dǎo)致整個(gè)TLB刷新的現(xiàn)象稱為"刷新TLB"。[0059]QEMU虛擬機(jī)實(shí)現(xiàn)的TLB是客戶機(jī)虛擬內(nèi)存到主機(jī)虛擬內(nèi)存的映射,但是相對(duì)而言,TLB的容量小的多。假設(shè)某計(jì)算機(jī)主存是4G,頁(yè)面大小為4K,那么內(nèi)存從邏輯上劃分成2~20塊;而TLB中表項(xiàng)一般不會(huì)多,在實(shí)際中很少會(huì)超過(guò)64個(gè)。因此,即使沒(méi)有進(jìn)程切換,也會(huì)發(fā)生TLB表項(xiàng)被覆蓋的現(xiàn)象。我們稱這種TLB表項(xiàng)被置換的現(xiàn)象為"刷新TLB表項(xiàng)"。[0060]由于DTLB所指向的拷貝頁(yè)的數(shù)量和TLB表項(xiàng)數(shù)目一致,所以無(wú)論是"刷新TLB表項(xiàng)"還是"刷新TLB"都會(huì)導(dǎo)致拷貝頁(yè)面被回收,而TLB指向的頁(yè)面可能依舊駐留在內(nèi)存中。由于拷貝頁(yè)面是動(dòng)態(tài)分配的,這樣就會(huì)導(dǎo)致TLB重新"指向"原頁(yè)面時(shí)得到不同的拷貝頁(yè)面。而虛擬多TLB系統(tǒng)在頁(yè)面被加載至內(nèi)存時(shí),會(huì)將TLB指向的頁(yè)面中的代碼語(yǔ)句及DTLB指向的拷貝頁(yè)中的數(shù)據(jù)語(yǔ)句覆蓋成0xF4。因此,在拷貝頁(yè)面被回收之前,必須進(jìn)行頁(yè)面寫(xiě)回的操作,即將原頁(yè)面中的數(shù)據(jù)語(yǔ)句寫(xiě)回到拷貝頁(yè)面,同時(shí)將拷貝頁(yè)面的代碼寫(xiě)回原頁(yè)面,如圖3所示。[0061]對(duì)于"刷新TLB表項(xiàng)"和"刷新TLB"這兩種不同的現(xiàn)象,寫(xiě)回策略有所不同。由于"刷新TLB"只是多次使用"刷新TLB表項(xiàng)"的寫(xiě)回策略,故只詳述"刷新TLB表項(xiàng)"的寫(xiě)回策略。具體如下:[0062]首先,依據(jù)TLB獲得即將被置換出內(nèi)存頁(yè)的相對(duì)虛擬地址(RelativeVirtualAddress,RVA);[0063]然后,根據(jù)RVA找出該內(nèi)存頁(yè)包含的數(shù)據(jù)語(yǔ)句及指令語(yǔ)句;[0064]接著,利用TLB和DTLB,計(jì)算出原頁(yè)面和拷貝頁(yè)面的起始地址;[0065]將原頁(yè)面中的數(shù)據(jù)語(yǔ)句寫(xiě)回到拷貝頁(yè)面,同時(shí)將拷貝頁(yè)面的指令語(yǔ)句寫(xiě)回原頁(yè)面中。[0066]內(nèi)核態(tài)和用戶態(tài)的同步[0067]QEMU虛擬系統(tǒng)中TLB的二維分別代表內(nèi)核態(tài)和用戶態(tài)。當(dāng)系統(tǒng)運(yùn)行在內(nèi)核態(tài)時(shí),通過(guò)tlb_table[0]和dtlb_addend[0]來(lái)完成地址映射;否則,用tlb_table[1]和dtlb_addend[1]代表虛擬多TLB。[0068]用戶態(tài)和內(nèi)核態(tài)的同步是指如果tlb_table[0][i]和tlb_table[l][i](其中i取0,1,…,255)指向同一個(gè)頁(yè)面,則必須將dtlb_addend[0][i]和dtlb_addend[1][i]也指向同一頁(yè)面。這又可以分為兩種情況,(1)頁(yè)面加載時(shí),不額外分配拷貝頁(yè)面;(2)刷新TLB表項(xiàng)時(shí),如果該頁(yè)面還有引用,則不能釋放其拷貝頁(yè)面。我們的應(yīng)對(duì)策略是在上述情況對(duì)應(yīng)的位置,先對(duì)頁(yè)面的引用數(shù)目進(jìn)行判斷,如果超過(guò)1,則不釋放拷貝頁(yè)面;否則釋放。[0069]寫(xiě)時(shí)復(fù)制(CopyOnWrite,C0W)的頁(yè)面同步[0070]cow表示對(duì)于多個(gè)調(diào)用者使用的相同資源(如代碼頁(yè)面),在某個(gè)調(diào)用者視圖修改資源時(shí),系統(tǒng)會(huì)為該調(diào)用者復(fù)制一份資源副本,而其他調(diào)用者所使用的資源仍然保持不變。由于代碼段不具備可寫(xiě)屬性,因此原則上允許若干個(gè)進(jìn)程共享代碼段,實(shí)際上,代碼段確實(shí)是共享段。但是,如果代碼段包含了像導(dǎo)入地址表(ImportAddressTable,IAT)這類在程序運(yùn)行時(shí)需要修改的數(shù)據(jù),就會(huì)觸發(fā)寫(xiě)時(shí)復(fù)制。由于IAT表保存的是庫(kù)函數(shù)相對(duì)庫(kù)文件的相對(duì)偏移,所以在庫(kù)文件被加載到指定內(nèi)存塊時(shí)(通常稱該內(nèi)存區(qū)域的起始地址為模炔基址),加載器需要將IAT修改為庫(kù)函數(shù)在內(nèi)存的地址(即偏移值加上模炔基址)。加載器修改IAT表的過(guò)程通常被稱為"IAT重寫(xiě)"。如果IAT表被合并在代碼段,那么在加載器修改IAT表時(shí)會(huì)觸發(fā)COW異常。為了提升包含IAT表的代碼頁(yè)(記為Pagel)的寫(xiě)權(quán)限,操作系統(tǒng)重新分配一個(gè)具有可寫(xiě)權(quán)限的頁(yè)面(記為Page2),同時(shí)填寫(xiě)TLB對(duì)應(yīng)表項(xiàng);之后,操作系統(tǒng)將Page1的數(shù)據(jù)完全拷貝到Page2中,此時(shí)加載器就可以對(duì)Page2進(jìn)行寫(xiě)操作了;完成重寫(xiě)IAT之后,操作系統(tǒng)會(huì)去刷新TLB表項(xiàng),使得用戶態(tài)指向Pagel的TLB表項(xiàng)指向具有寫(xiě)權(quán)限的Page2頁(yè)面。完成整個(gè)COW的處理過(guò)程之后,處理器又將切回用戶態(tài)繼續(xù)執(zhí)行。在虛擬多TLB的系統(tǒng)中,由于頁(yè)面加載時(shí)就分別對(duì)TLB和DTLB指向的頁(yè)面中的指令語(yǔ)句和數(shù)據(jù)語(yǔ)句進(jìn)行了覆蓋,這將會(huì)導(dǎo)致頁(yè)面拷貝時(shí)得到的數(shù)據(jù)不正確,即引發(fā)虛擬多TLB不同步。[0071]在對(duì)C0W進(jìn)行深入的分析之后,發(fā)現(xiàn)C0W引發(fā)的虛擬多TLB不同步的問(wèn)題很容易解決。如圖4,我們只需要在QEMU執(zhí)行缺頁(yè)異常處理程序時(shí)(即QEMU的tlb_set_page〇函數(shù)),進(jìn)行異常檢測(cè)。在QEMU中,觸發(fā)異常的頁(yè)面的起始地址被保存在處理器的cr2寄存器,即enV->Cr[2];而且,如果是寫(xiě)不可寫(xiě)頁(yè)面(如只讀頁(yè)面或只執(zhí)行頁(yè)面)導(dǎo)致的異常,處理器中的W_ERROR_BIT(COW標(biāo)志)會(huì)被置位。因此,在進(jìn)行覆蓋操作之前,判斷處理器中的W_ERROR_BIT位是否被置位。如果是就觸發(fā)了C0W異常,不做覆蓋任理;否則,覆蓋TLB和DTLB指向的內(nèi)存頁(yè)面。[0072]通過(guò)以上方法,區(qū)分了系統(tǒng)中進(jìn)程對(duì)內(nèi)存中指令語(yǔ)句和數(shù)據(jù)語(yǔ)句的訪問(wèn),并分別限制訪問(wèn)權(quán)限,使其不能讀指令語(yǔ)句和執(zhí)行數(shù)據(jù)語(yǔ)句;當(dāng)系統(tǒng)出現(xiàn)代碼復(fù)用攻擊時(shí):[0073]1、攻擊指令在內(nèi)存空間加載的語(yǔ)句中搜索可鏈接成執(zhí)行序列的語(yǔ)句序列;[0074]2、搜索到可用的語(yǔ)句序列后,攻擊指令通過(guò)快表TLB,從而獲得語(yǔ)句序列在內(nèi)存中的訪問(wèn)地址;[0075]3、由于本發(fā)明采用的TLB和DTLB實(shí)現(xiàn)了內(nèi)存頁(yè)讀和執(zhí)行權(quán)限的分離;[0076]4、TLB中僅有可讀可寫(xiě)的數(shù)據(jù)語(yǔ)句,DTLB中僅有可執(zhí)行的指令語(yǔ)句;攻擊指令無(wú)法通過(guò)完整的代碼段獲得語(yǔ)句序列,而鏈接成執(zhí)行序列,從而無(wú)法發(fā)動(dòng)攻擊;因此系統(tǒng)有效防御了代碼復(fù)用攻擊,為用戶提供健壯的系統(tǒng)安全保障。[0077]本領(lǐng)域的技術(shù)人員容易理解,以上所述僅為本發(fā)明的較佳實(shí)施例而已,并不用以限制本發(fā)明,凡在本發(fā)明的精神和原則之內(nèi)所作的任何修改、等同替換和改進(jìn)等,均應(yīng)包含在本發(fā)明的保護(hù)范圍之內(nèi)?!局鳈?quán)項(xiàng)】1.一種代碼復(fù)用攻擊的防御方法,其特征在于,包括以下步驟:51.在庫(kù)文件中增加新段,令所述新段中保存的語(yǔ)句為庫(kù)文件的代碼段的數(shù)據(jù)語(yǔ)句;52.將所述庫(kù)文件加載至內(nèi)存;53.將所述庫(kù)文件的代碼段分別加載至內(nèi)存中只讀的內(nèi)存頁(yè)以及只執(zhí)行的內(nèi)存頁(yè);通過(guò)所述新段中保存的語(yǔ)句,判斷加載后的代碼段中的語(yǔ)句是否為數(shù)據(jù)語(yǔ)句,并將所述只讀的內(nèi)存頁(yè)中的非數(shù)據(jù)語(yǔ)句以及只執(zhí)行的內(nèi)存頁(yè)中的數(shù)據(jù)語(yǔ)句替換為無(wú)效語(yǔ)句。2.如權(quán)利要求1所述的防御方法,其特征在于,步驟S1包括如下子步驟:511.將庫(kù)文件的代碼段的數(shù)據(jù)語(yǔ)句儲(chǔ)存于臨時(shí)文件;512.在庫(kù)文件中增加新段,并將臨時(shí)文件中儲(chǔ)存的數(shù)據(jù)語(yǔ)句復(fù)制至新段。3.如權(quán)利要求2所述的防御方法,其特征在于,所述步驟SI1具體為:根據(jù)庫(kù)文件的代碼段的語(yǔ)句的操作碼是否為空,判斷該語(yǔ)句是否為數(shù)據(jù)語(yǔ)句,是則將該語(yǔ)句儲(chǔ)存入臨時(shí)文件,否則對(duì)該語(yǔ)句不作任何處理。4.如權(quán)利要求2所述的防御方法,其特征在于,所述步驟S12具體為:將庫(kù)文件的頭部中的段的數(shù)值+1;在庫(kù)文件的boundimport段以及security段之前插入新段,令所述新段中保存的語(yǔ)句為臨時(shí)文件中的數(shù)據(jù)語(yǔ)句;修改庫(kù)文件的頭字節(jié)以及校驗(yàn)和。5.如權(quán)利要求1所述的防御方法,其特征在于,所述方法用于基于windows平臺(tái)的虛擬系統(tǒng)?!疚臋n編號(hào)】G06F21/56GK106096407SQ201610375304【公開(kāi)日】2016年11月9日【申請(qǐng)日】2016年5月31日【發(fā)明人】李偉明,王文清【申請(qǐng)人】華中科技大學(xué)