專利名稱:通過實施數(shù)據(jù)流完整性來保護軟件的制作方法
技術(shù)領(lǐng)域:
本說明書一般涉及計算機編程領(lǐng)域。更具體地,本說明書涉及對于針對計算機應(yīng)用程序或系統(tǒng)組件的攻擊的保護;它具體涉及但不限于通過實施數(shù)據(jù)流完整性來保護軟件。它還涉及通過發(fā)現(xiàn)編程錯誤(即使這樣的錯誤未被攻擊利用)而使得軟件更為可靠。
背景
大多數(shù)軟件以諸如C和0++的不安全語言編寫,在這些語言中緩沖區(qū)溢出、格式串具易受攻擊性以及其他易受攻擊性存在,且可能被攻擊者利用,使得安全或隱私侵犯成為可能。即使以安全類型的語言編寫的程序也具有以不安全語言編寫的庫和運行時環(huán)境。從而,當(dāng)前的軟件易于受到各種攻擊,且在可預(yù)見的將來它仍可能保持易受攻擊。
大多數(shù)這樣的軟件攻擊利用軟件易受攻擊性或缺陷將數(shù)據(jù)寫到非預(yù)期的位置中。例如,控制數(shù)據(jù)攻擊利用緩沖區(qū)溢出或其他易受攻擊性來重寫棧中的返回地址、函數(shù)指針或某些其他控制數(shù)據(jù)。非控制數(shù)據(jù)攻擊利用類似的易受攻擊性來重寫安全關(guān)鍵數(shù)據(jù)而不會破壞程序中的預(yù)期控制流。非控制數(shù)據(jù)攻擊被認為與控制數(shù)據(jù)攻擊相比較不頻繁,但它們同等嚴重,且在目前沒有已知的針對它們的良好防范。
以往,建議使用防止軟件攻擊的C的存儲器安全的語言分支。然而,這些方法要求現(xiàn)有的C代碼被傳入到這些分支中,這并非是平凡的任務(wù),且會發(fā)生對C運行時環(huán)境的顯著改變。
其他已知的方法可應(yīng)用于現(xiàn)有的程序,但這些方法一般不針對非控制數(shù)據(jù)攻擊進行防范和/或具有假陽性并在沒有硬件支持的情況下導(dǎo)致非常高的開銷。
概述下面提供本發(fā)明的簡化概要以便為讀者提供基本的理解。本概要不是本發(fā)明的詳盡概觀,并且既不標識本發(fā)明的關(guān)鍵/決定性要素也不描繪本發(fā)明的范圍。其唯一目的是以簡化形式提供在此公開一些概念作為稍后提供的更詳細描述的序言。
大多數(shù)軟件攻擊利用軟件易受攻擊性或缺陷將數(shù)據(jù)編寫到非預(yù)期的位置中。例如,控制數(shù)據(jù)攻擊利用緩沖區(qū)溢出或其他易受攻擊性來重寫棧中的返回地址、函數(shù)指針或某些其他控制數(shù)據(jù)。非控制數(shù)據(jù)攻擊利用類似的易受攻擊性來重寫安全關(guān)鍵數(shù)據(jù)而不會破壞程序中的預(yù)期控制流。描述用于針對控制數(shù)據(jù)和非控制數(shù)據(jù)攻擊兩者來保護軟件的方法。執(zhí)行靜態(tài)分析以確定軟件程序的數(shù)據(jù)流信息。形成數(shù)據(jù)流跟蹤指令以便在該軟件的執(zhí)行或仿真期間跟蹤數(shù)據(jù)流。而且,形成檢查指令以針對靜態(tài)分析結(jié)果檢査所跟蹤的數(shù)據(jù)流并由此標識潛在的攻擊或錯誤。描述可任選的優(yōu)化來減少產(chǎn)生的額外開銷。
本示例提供一種方法,包括以下步驟
提供對軟件程序的靜態(tài)分析的結(jié)果的訪問,靜態(tài)分析結(jié)果包括數(shù)據(jù)流信
息;
形成數(shù)據(jù)流跟蹤指令以便跟蹤軟件內(nèi)的數(shù)據(jù)流;以及
形成檢查指令以針對靜態(tài)分析結(jié)果檢查所跟蹤的數(shù)據(jù)流并由此標識軟件程序中的潛在缺陷。
通過以此方式實施數(shù)據(jù)流完整性,我們能夠檢測控制數(shù)據(jù)攻擊和非控制數(shù)據(jù)攻擊兩者。與此相對,設(shè)法實施控制流完整性的己知方法僅能針對控制數(shù)據(jù)攻擊進行保護。術(shù)語"軟件程序中的缺陷"用來指示軟件程序上的潛在攻擊和/或軟件程序中的編程錯誤。
提供了一種相應(yīng)的裝置,包括
被安排成訪問對軟件程序的靜態(tài)分析的結(jié)果的輸入,靜態(tài)分析結(jié)果包括數(shù)據(jù)流信息;
被安排成形成數(shù)據(jù)流跟蹤指令以便跟蹤軟件內(nèi)的數(shù)據(jù)流的處理器;以及
被安排成形成檢查指令以針對靜態(tài)分析結(jié)果檢査所跟蹤的數(shù)據(jù)流并由此標識軟件程序中潛在的缺陷的處理器。
在另一示例中,提供由軟件程序的最終用戶執(zhí)行的、被安排成實施數(shù)據(jù)流完整性的方法。例如, 一種方法包括
訪問軟件程序的靜態(tài)分析的結(jié)果,靜態(tài)分析結(jié)果包括數(shù)據(jù)流信息;
在軟件程序執(zhí)行或仿真期間跟蹤該軟件程序中的數(shù)據(jù)流;以及
針對靜態(tài)分析結(jié)果檢査所跟蹤的數(shù)據(jù)流,并作出是否找到失配的指示。
提供了相應(yīng)的裝置。
一種裝置,包括
被安排成訪問對軟件程序的靜態(tài)分析的結(jié)果的輸入,靜態(tài)分析結(jié)果包括 數(shù)據(jù)流信息;
被安排成在軟件程序執(zhí)行或仿真期間跟蹤該軟件程序中的數(shù)據(jù)流的處
理器;以及
其中,該處理器還被安排成針對靜態(tài)分析結(jié)果檢查所跟蹤的數(shù)據(jù)流,并 作出是否找到失配的指示。
優(yōu)選地,數(shù)據(jù)流跟蹤指令和檢査指令使用修改的編譯器或二進制重寫工具 中的任何一個來添加到軟件。在另一示例中,這些指令使用被安排成仿真執(zhí)行 軟件程序的處理器的機器仿真程序以及機器仿真程序的硬件等價物中的任何 一個實現(xiàn)。
優(yōu)選地,潛在的攻擊包括控制數(shù)據(jù)攻擊和非控制數(shù)據(jù)攻擊兩者。
例如,針對由軟件程序中的指令讀取的每一值,靜態(tài)分析結(jié)果包括來自該 軟件程序的可寫該值的指令集合。
在某些實施例中,該方法還包括通過根據(jù)軟件程序的源代碼計算到達定義 (reaching definitions)來執(zhí)行軟件程序的靜態(tài)分析。
優(yōu)選地,數(shù)據(jù)流跟蹤指令被安排成維護標識符和存儲器位置之間的映射, 標識符是對寫到每一存儲器位置的最后一條指令的標識符。
例如,檢查指令操縱(instrument)讀指令。
優(yōu)選地,操縱讀指令以檢查寫正在讀取值的指令的標識符是否是靜態(tài)分析 所計算出的相關(guān)聯(lián)集合中的元素。
在一實施例中,該方法還包括確定指令的等價類,并向同一類中的所有指 令分派同一標識符。
在一示例中,該方法包括基于第二靜態(tài)分析移除某些數(shù)據(jù)流跟蹤指令和某些檢查指令。
示例提供了一種包括計算機程序代碼裝置的計算機程序,該計算機程序代 碼裝置適于當(dāng)所述程序在計算機上運行時執(zhí)行上述任何方法的所有步驟。例 如,該計算機程序被包含在計算機可讀介質(zhì)上。
對于裝置示例
裝置例如包括被安排成通過根據(jù)軟件程序的源代碼計算到達定義來執(zhí)行 軟件程序的靜態(tài)分析的編譯器。
優(yōu)選地,處理器被安排成形成數(shù)據(jù)流跟蹤指令以維護標識符和存儲器位置 之間的映射,標識符是對寫到每一存儲器位置的最后一條指令的標識符。
優(yōu)選地,處理器被安排成添加檢查指令,使得它們操縱讀指令。
優(yōu)選地,處理器被安排成對每一讀指令形成檢查指令,以檢査寫正在讀取 值的指令的標識符是否是靜態(tài)分析所計算出的相關(guān)聯(lián)集合中的元素。
該方法可由存儲介質(zhì)上機器可讀形式的軟件執(zhí)行。軟件可適于在并行處理 器或串行處理器上執(zhí)行以使得各方法步驟可按任何合適的次序或同時執(zhí)行。
這確認了軟件可以是有價值的、可單獨交易的商品。其旨在涵蓋運行于或 者控制"啞(dumb)"或者標準硬件以實現(xiàn)期望功能的軟件,(因此,軟件在本 質(zhì)上定義了軟件安全系統(tǒng)的功能,并且從而可被稱為軟件安全系統(tǒng),即使是在 它與其標準硬件結(jié)合之前)。出于類似的理由,它還旨在包含例如用于設(shè)計硅
芯片,或者用于配置通用可編程芯片的HDL (硬件描述語言)軟件等"描述"
或者定義硬件配置以實現(xiàn)期望功能的軟件。為出于避免疑義的目的,本發(fā)明涵 蓋其中以硬件而非軟件實現(xiàn)本系統(tǒng)任何部分的實現(xiàn)。
許多附帶特征將隨著參考下面的詳細描述并結(jié)合附圖進行理解而得到更 好的認識。
結(jié)合附圖閱讀以下詳細描述,將更好地理解本說明書,在附圖中:
圖1是計算機所使用的存儲器的示意圖lb是棧的一部分的示意圖1C是計算機存儲器的一部分的示意圖;圖2是保護軟件的方法的流程圖; 圖3是靜態(tài)分析的方法的流程圖4是維護映射數(shù)據(jù)結(jié)構(gòu)以及檢查軟件程序完整性的方法的流程圖5是用于保護軟件的經(jīng)修改編譯器的示意圖6是用于保護軟件的二進制重寫工具的示意圖7是用于保護軟件的機器仿真程序的示意圖8是使用圖7的用于保護軟件的機器仿真程序的方法的流程附圖中使用相同的附圖標記來指代相同的部分。
詳細描述
下面結(jié)合附圖提供的詳細描述旨在作為對本示例的描述,而非表示用于解 釋或利用本示例的唯一形式。本說明書闡述本示例的功能以及用于構(gòu)造和操作 本示例的步驟序列。然而,相同或等價的功能與序列可由不同的示例來實現(xiàn)。
認識到需要針對控制數(shù)據(jù)和非控制數(shù)據(jù)攻擊兩者來保護軟件。提供通過實 施數(shù)據(jù)流完整性進行操作而實現(xiàn)保護的方法。為了更好地理解控制數(shù)據(jù)攻擊和 非控制數(shù)據(jù)攻擊,參考圖l、 lb和lc討論一示例。
圖1是包括操作系統(tǒng)專用存儲器1、用戶存儲器B和可用存儲器A (如計 算機處理器所見)的計算機存儲器的一部分的示意圖。操作系統(tǒng)存儲器l不可 用于除計算機的操作系統(tǒng)以外的任何其他用途。用戶存儲器可用于由用戶安裝 的軟件應(yīng)用程序,例如在圖1的示例中可為此目的占用存儲器中的某些塊(見 塊C)。在圖1的下部更詳細示出了可用存儲器A。它包括按照箭頭方向填充 且可被認為是計算機的工作存儲器的棧2和堆3。計算機存儲器可被認為示意 性地使用"空穴"(pigeonhole)存儲器模型,由此各信息項目被存儲在各存儲 單元中,其各自具有唯一的地址或標識符。例如,圖lc示出了兩行這樣的空 穴。
現(xiàn)在考慮以下給出的用計算機編程語言C編寫的示例代碼片段。 1: int authenticated = 0; 2: char packet [1000];4: while (! authenticated) { 5: PacketRead(packet》 6:
7: if (Authenticate(packet)) 8: authenticated = 1;
9:} 10:
11: if (authenticated)
12: ProcessPacket(packet);
這包括編號為1到12的12行代碼。在行1中,定義整數(shù)變量,并設(shè)置為 值0。在行2中,設(shè)置稱為packet (分組)的1000字節(jié)的字符值數(shù)組,且分派 IOOO字節(jié)的存儲器供該數(shù)組使用。While循環(huán)然后在行4開始,并繼續(xù)直到 行9。 While循環(huán)的條件是變量authenticated (經(jīng)認證)的值是否為0。此時, authenticated的值為0,在行1中剛剛被設(shè)置為0。繼續(xù)前進到行5,并對自變 量packet執(zhí)行函數(shù)PacketRead (分組讀取)。該函數(shù)將一 packet讀入到已在行 2中定義的數(shù)組packet。在行7,調(diào)用函數(shù)Authenticate (認證)來檢査所讀入 的packet,且如果結(jié)果成功,則將變量authenticated的值置為1 (見行8)。在 行11和12,然后使用函數(shù)ProcessPacket (處理分組)來處理經(jīng)認證的packet。 然而,假定函數(shù)PacketRead能夠?qū)acket寫1000以上的字節(jié),正如在諸如C 和。++等眾多計算機語言的情況??衫迷撘资芄粜詠碇貙懞瘮?shù)PacketRead 的返回地址或重寫authenticated這現(xiàn)在將參考圖1和lb來說明。假定以上包 括12行代碼的軟件應(yīng)用程序存儲在圖1的用戶存儲器B中,并假設(shè)調(diào)用函數(shù) PacketRead的行5被存儲在D。該行調(diào)用函數(shù)PacketRead,該函數(shù)例如被存儲 在E。作為調(diào)用E處的PacketRead的結(jié)果,讀入一 packet,并存儲在棧上,如 圖lb中的4,帶有之前存儲在棧上5處的變量authenticated的值,以及存儲在 棧上6處的返回地址(D的地址,即調(diào)用PacketRead且控制流所返回的指令的 地址)的值R。如果所讀入的packet大于1000字節(jié),則它可重寫圖lb中的存 儲單元5和6。通過重寫返回地址R,攻擊者能夠阻止程序返回到行5并繼續(xù) 程序。攻擊者可將程序的控制流轉(zhuǎn)向到存儲器的其他部分,并因此破壞安全性和/或隱私。這是可允許攻擊者獲得對執(zhí)行的控制的控制數(shù)據(jù)攻擊的一種形式。
通過重寫變量authenticated的值,攻擊者能夠使while循環(huán)停止迭代,以代替 迭代直到認證成功。攻擊者然后能夠使其packet在沒有正確認證的情況下得到 處理。這是非控制數(shù)據(jù)攻擊的一種形式。
如上所述,我們的方法包括實施數(shù)據(jù)流完整性。在高層,我們的方法包括 計算或訪問預(yù)先計算的靜態(tài)數(shù)據(jù)流(見圖2的框10)并運行程序操縱過程(見 圖2的框12),以便操縱程序(向其添加指令)來跟蹤數(shù)據(jù)流和檢査該動態(tài)數(shù) 據(jù)流的完整性。該操縱包括添加數(shù)據(jù)流跟蹤指令來跟蹤動態(tài)數(shù)據(jù)流。它還包括 添加檢査指令來針對靜態(tài)數(shù)據(jù)流信息檢査動態(tài)數(shù)據(jù)流。然后可使所操縱的程序 運行,且如果數(shù)據(jù)流完整性被侵犯,則會發(fā)生異常、警報或停止工作。
靜態(tài)分析包括針對給定軟件程序確定數(shù)據(jù)流信息。例如,對每一程序位置 (諸如以上代碼示例中的行號),靜態(tài)分析計算可能在所關(guān)注的程序位置寫值 的程序位置的集合。因此例如,程序位置行4包括變量authenticated。該變量 可在行1或行8寫入。因此,對行4的靜態(tài)分析結(jié)果包括集合{1,8},對行l(wèi)l 則還包括{1,8}。在簡化的示例中,程序位置的集合以此方式對每一行號產(chǎn)生以 給出完整的靜態(tài)分析的結(jié)果。更一般地,靜態(tài)分析可被表述為對由指令讀取的 每一值計算可寫該值的指令集合。如將在以下更詳細描述地,靜態(tài)分析結(jié)果集 合在特定的示例中與編譯器對程序的中伺表示中的指令而非源代碼行號相關(guān) 聯(lián)。為清楚起見,在以上引用源代碼行號。
可使用計算這些值的集合的任何合適的方法。例如,可使用如由Aho、Sethi 和Ullman在1986年Addison Wesley出版社ISBN 0-201-10194-7的"Compilers: Principles, Techniques and Tools (編譯器原理、技術(shù)和工具),,中所述的到達 定義分析。如由Aho等人展示的到達分析定義介紹了以下語言。寫存儲單元的 指令定義該存儲單元中的值,而從存儲單元中讀值的指令被稱為使用該值。分 析對每一使用計算到達定義的集合。它向每一定義分派標識符,并返回每一使
用的到達定義標識符的集合。
例如,在行4和11使用了 authenticated如果在源代碼中運行到達定義分 析,則可能得出行1和8中的定義到達兩個使用的結(jié)論。因此,如果使用行號 來標識定義,則這兩個使用的到達定義標識符的集合將是{1,8}。分析可能不是精確的,但分析是保守的,這一點是重要的。它必須在集合 中包括在運行時可能到達使用的所有定義,但它可包括其他定義。例如,僅行 8中的定義可能到達行11中的使用,但分析可計算到達定義集合{1,8}。確保 數(shù)據(jù)流完整性實施不具有假陽性是重要的。
如上所述,(例如,通過添加指令來)操縱要保護的程序以跟蹤數(shù)據(jù)流并 檢查所跟蹤的數(shù)據(jù)流是否遵循靜態(tài)分析結(jié)果。添加指令的過程,此處稱為操縱, 是使用經(jīng)修改的編譯器、二進制重寫工具、機器仿真程序、專用硬件中的任一 項或按照任何其他合適的方式實現(xiàn)的。換言之,操縱程序以在運行時計算到達 每個讀取的定義并計算該定義是否位于靜態(tài)計算的到達定義標識符的集合中。 為了在運行時計算到達定義,維護記錄寫到每一存儲單元的最后一條指令的標
識符的運行時定義表(RDT)。操縱每個寫以更新RDT。讀取之前的操縱使用 正在讀取存儲單元的地址來從RDT檢索標識符。然后,它檢査該標識符是否 位于靜態(tài)計算的集合中。例如,在以上的C代碼片段示例中,將添加代碼以在 行8中將RDT[&authenticated]置為8, 并檢査在行4和11中 RDT[&authenticated]e {1,8}是否成立。
現(xiàn)在將參考圖lc對此進行示意性地說明。假定到達以上示例程序的行8, 且變量authenticated的值被置為1。這包括向存儲器寫入一值以表示該變量的 值。例如,如圖lc所示,向存儲單元101寫X。假定形成相關(guān)存儲器,其由 圖lc的空穴存儲器的下面一行指示。在與存儲單元101相關(guān)聯(lián)的存儲單元102 中,存儲關(guān)于程序位置行8的信息,在那里出現(xiàn)寫變量authenticated的指令。 存儲在相關(guān)存儲器中的這種信息是數(shù)據(jù)流跟蹤信息的示例。為了在相關(guān)存儲器 中存儲這一信息,將數(shù)據(jù)流跟蹤指令添加到示例程序。
在程序執(zhí)行中稍后到達行11。在此行中,給出讀取變量authenticated的值 的指令。在進行該讀取之前,對相關(guān)存儲器中的存儲單元102處的入口是否與 靜態(tài)數(shù)據(jù)流信息一致作出檢査。該檢査是使用添加到程序的檢査指令來作出 的。如上所述,對每一程序位置(例如,行),靜態(tài)數(shù)據(jù)流信息包括可能寫入 當(dāng)前行上的值的行號的集合。在行11的情況中,值的集合為{1,8},如圖lc 所示。這些行號1、 8是以下更詳細描述的到達定義標識符的示例。因為存儲 單元102 (對應(yīng)于存儲單元101)中的入口包含作為該集合的成員的值,因此在這種情況中不需要作出任何指示。然而,如果發(fā)生了攻擊,則如上所述,(例
如)變量authenticated的值和/或PacketRead的返回地址可能被重寫了 。
在這種情況中,相關(guān)存儲單元102中的值是z而非如圖lc的8。這是因 為,在z行,當(dāng)重寫變量authenticated時,PacketRead函數(shù)寫存儲單元101 。 從而在行l(wèi)l處或在行l(wèi)l之前,發(fā)生異常,因為值z不是適當(dāng)?shù)撵o態(tài)分析結(jié)果 集{1,8}的成員。通過重寫PacketRead的返回地址,程序執(zhí)行不會在計算行5 之后返回到行6。然而,因為在程序讀返回地址之前,以類似于以上對變量 authenticated所述的方式在相關(guān)存儲器中作出檢査,所以檢測到該錯誤。該檢 査標記錯誤,因為從中讀返回地址的程序位置在對應(yīng)于返回地址的相關(guān)存儲單 元中具有值z。如下所述,該相關(guān)存儲單元在函數(shù)入口上被置為零,并在函數(shù) 返回時添加它是否為O的檢查。當(dāng)攻擊重寫返回地址時該檢查失敗,因為相關(guān) 聯(lián)的相關(guān)存儲器具有值z。
因此,在圖lc中,由空穴下面一行表示的'相關(guān)'存儲器是如上所述的運行 時定義表(RDT)的一部分的示例。
為了在存在可在任何地方寫入且甚至可能執(zhí)行數(shù)據(jù)的強大攻擊者的情況 下實施數(shù)據(jù)流完整性,要防止篡改RDT、篡改代碼或繞開操縱。這以任何合適 的方式實現(xiàn)。
例如,通過操縱寫來檢查目標地址是否位于分派給RDT的存儲器區(qū)域之 內(nèi)來防止RDT篡改。寫RDT的任何嘗試會生成異常。在另一示例中,用同樣 的檢查或通過使用對代碼頁的只讀保護來防止代碼篡改。
保護RDT的另一方法包括修改程序,以使得所寫的地址中沒有一個可引 用包含RDT的存儲器。例如,如果在地址4000000h保存RDT且沒有其他程 序可訪問數(shù)據(jù)結(jié)構(gòu)在4000000h上方,則可通過使要由程序?qū)懙拿恳坏刂放c 3FFFFFFh進行邏輯AND來保護RDT。
為了防止攻擊者繞開操縱,要防止篡改間接控制流轉(zhuǎn)移的目標地址。如前 所述,操縱對程序員定義的控制數(shù)據(jù)的寫和讀。此外,以相同方式操縱對由編 譯器添加的控制數(shù)據(jù)的寫和讀。例如,將返回地址的RDT入口設(shè)置為公知的 值,檢查該入口在返回時是否仍保持該值。
相對于未受操縱的軟件增加了開銷。例如,對向存儲器的每一寫入,發(fā)生對相關(guān)存儲器的另一寫入(圖lc)。然而,有可能為較低的開銷而對覆蓋面進行折衷。如果數(shù)據(jù)流圖沒有為某些使用指定到達定義,則可能不會檢測出某些攻擊,因為這些使用未被操縱,但開銷會降低。如果操縱了對控制數(shù)據(jù)的使用,則仍能確保數(shù)據(jù)流完整性。在示例中,我們的方法僅操縱對局部變量的使用而沒有操縱函數(shù)外的定義和控制數(shù)據(jù)的使用。該示例是有意思的,因為它具有低開銷且它仍能捕捉眾多有意思的攻擊。例如,它可防止侵犯控制流完整性的任何攻擊和上述非控制數(shù)據(jù)攻擊示例。
當(dāng)所操縱的程序運行時,對靜態(tài)計算出的數(shù)據(jù)流圖的任何偏離會造成異常。由于分析是保守的,不存在任何假陽性。如果有異常,則程序具有可能是潛在攻擊或編程錯誤的錯誤。
圖4是維護映射數(shù)據(jù)結(jié)構(gòu)以及檢查軟件程序完整性的方法的流程圖。該流程圖的上半部涉及完整性檢查過程,下半部涉及現(xiàn)在將說明的數(shù)據(jù)流跟蹤過
程。執(zhí)行要保護的軟件程序在位置l處的指令(見框30)。對在程序位置l讀取并在位置a存儲(見框31)的每個變量v,作出查看相應(yīng)的相關(guān)存儲器中的入口 da是否是在對適當(dāng)程序位置的靜態(tài)分析期間確定的程序位置的集合的成員(見框32)。如果找到矛盾,則信令錯誤(見框33)。可用任何合適的方式信令該錯誤。例如,發(fā)生異常,則終止過程或?qū)懻{(diào)試日志。如果l處的每一變量成功地通過了檢查(見結(jié)束框34),則繼續(xù)數(shù)據(jù)跟蹤過程。對在程序位置1處所寫的每個存儲器或寄存器地址a,這包括將適當(dāng)?shù)南嚓P(guān)存儲單元的內(nèi)容更新為l (見框36,將da更新為l)。"結(jié)束"過程(見框37)完成該過程。
如上所述,可使用經(jīng)修改的編譯器或二進制重寫工具來實現(xiàn)操縱。也有可能使用機器仿真程序或機器仿真程序的硬件等價物。現(xiàn)在將參考圖5到8更詳細地描述這些示例。在這些示例的每一個中,編譯器、二進制重寫工具、機器仿真程序或硬件等價物是使用合適的計算機以及本領(lǐng)域中己知的合適的操作系統(tǒng)軟件一起實現(xiàn)的。
圖5是用于保護軟件的經(jīng)修改編譯器的示意圖。要保護的軟件程序的源代碼50被輸入到執(zhí)行靜態(tài)分析并計算靜態(tài)數(shù)據(jù)流的過程中(見框51)。來自靜態(tài)分析的關(guān)于數(shù)據(jù)流的這一信息被提供給具有相關(guān)聯(lián)處理器54的經(jīng)修改編譯器52。該經(jīng)修改編譯器每當(dāng)寫寄存器或存儲器地址a時即發(fā)出代碼。該代碼維護一數(shù)據(jù)結(jié)構(gòu),其將每一寄存器或存儲器地址a映射到在動態(tài)執(zhí)行中寫該寄存
器或存儲器單元的當(dāng)前值的程序位置的標識符da (如上所述)。此外,編譯器 每當(dāng)存儲在存儲器或寄存器地址a的變量v在某一地址1使用時即發(fā)出檢査數(shù) 據(jù)流完整性的代碼。該代碼檢査da是否是Slv中的位置中的一個。它在該數(shù)據(jù) 結(jié)構(gòu)中查找值da,并檢査它是否在Slv中。Slv中位置的標識符可被嵌入代碼 中,或者可在將變量和位置映射到位置集合的表中査找它們。第一種方法能夠 產(chǎn)生特別好的性能,且阻止攻擊者重寫表。在任一情況中,如果檢查失敗,則 發(fā)出的代碼例如通過發(fā)生異常來信令錯誤。
經(jīng)修改編譯器的輸出是具有集成的數(shù)據(jù)流完整性功能的可執(zhí)行軟件53。 以此方式,可按照簡化且有效的方式向現(xiàn)有源代碼提供數(shù)據(jù)流完整性功能。
圖6是用于保護軟件的二進制重寫工具62的示意圖。這采用可執(zhí)行代碼 60作為輸入,并能夠訪問如上所述的靜態(tài)分析的結(jié)果61。在此示例中,使用 靜態(tài)數(shù)據(jù)流信息61來驅(qū)動二進制重寫工具62發(fā)出檢查動態(tài)數(shù)據(jù)流完整性的代 碼,如上對基于編譯器的實現(xiàn)所述。以此方式,有可能對以往釋放的二進制代 碼添加數(shù)據(jù)流完整性功能。二進制重寫工具62的輸出包括經(jīng)修改的可執(zhí)行代 碼63。
圖7是用于保護軟件的機器仿真程序70的示意圖。這采用靜態(tài)數(shù)據(jù)流信 息61作為輸入,以及可執(zhí)行代碼60用于保護。機器仿真程序70仿真軟件執(zhí) 行,并發(fā)生錯誤或異常71??墒褂迷摲椒ㄏ蛑搬尫诺亩M制代碼添加檢測。 如現(xiàn)在將參考圖8所述,機器仿真程序維護兩個數(shù)據(jù)結(jié)構(gòu)80、 81。第一數(shù)據(jù)結(jié) 構(gòu)80即映射1,將每一存儲器和寄存器地址a映射到標識符da,且每當(dāng)它仿 真寫寄存器或存儲器的CPU指令時它都更新該數(shù)據(jù)結(jié)構(gòu)(見框82)。該機器 仿真程序也保存第二數(shù)據(jù)結(jié)構(gòu)81 (映射2),這將變量的使用映射到所確定的 靜態(tài)分析可寫所使用的值的集合Slv或位置。當(dāng)仿真程序處理位置1處的讀存 儲在寄存器或存儲器地址a處的變量v的指令時,它在映射2中查找Slv,并 在第一數(shù)據(jù)結(jié)構(gòu)即映射1中查找最后一次寫該變量的位置da (見框83)。如 果da不在Slv中(見框84),則仿真程序例如通過調(diào)用適當(dāng)?shù)腻e誤句柄來信 令錯誤(見框85)。
在另一實施例中,數(shù)據(jù)流完整性功能是使用與上述用于機器仿真程序相同的技術(shù)或任何其他合適的技術(shù)以硬件實現(xiàn)的。該方法允許數(shù)據(jù)流完整性功能被 添加到之前釋放的二進制代碼。
通過使用參考圖5到8描述的任何方法,可保護軟件程序免受攻擊。不必 使用特定的安全語言分支來導(dǎo)入舊的應(yīng)用程序或?qū)懶碌膽?yīng)用程序。也能夠保護 程序中的所有數(shù)據(jù)流而非僅僅諸如函數(shù)指針等程序的特定部分。能夠針對不改 變目標程序的控制流的攻擊成功。有利地,我們的方法的特定實施例不會生成 假陽性。
現(xiàn)在給出關(guān)于靜態(tài)分析的更多細節(jié)。 靜態(tài)分析
如上所述,靜態(tài)分析包括數(shù)據(jù)流信息,諸如對由指令讀取的每一值包括關(guān) 于可寫該值的指令的集合的信息。圖3是靜態(tài)分析的示例方法的流程圖。
對每個程序位置1(見框20),以及在該程序位置l使用的每個變量v(見 框21),獲取關(guān)于程序位置Slv的集合的信息。例如,可能寫在l處使用的值 v的程序位置Slv的集合。在某些示例中,使用關(guān)于程序位置的類的信息或關(guān) 于程序位置的其他信息,如將在以下更詳細描述地。在圖3中為完整起見示出 兩個"結(jié)束"語句(見框23和24)。
如上所述,計算關(guān)于程序位置的集合的信息的步驟可包括使用到達定義分 析。在特定示例中,使用兩種分析的組合流程敏感的過程內(nèi)分析以及流程不
敏感且上下文不敏感的過程間分析。
過程內(nèi)分析考慮流程控制。在一示例中,它可通過遍歷如Appel,A.W.在 1998年劍橋大學(xué)出版社的"Modern Compiler Implementation in Java (使用Java 的現(xiàn)代編譯器實現(xiàn))"中所述的靜態(tài)單個分派表示來實現(xiàn)。使用這種分析來為 在聲明它們的函數(shù)之外沒有定義的局部變量的使用計算到達定義。使用過程間 分析來對所有其他使用計算到達定義。
過程間分析較不精確,以允許它放大到大型程序。它忽略控制流,且在分 析函數(shù)時它不考慮進行調(diào)用的上下文。實現(xiàn)指向分析來計算每一指針可指向的 對象的集合,且使用這些指向集合來計算到達定義。在1994年哥本哈根大學(xué) Andersen, L.的博士論文"Program Analysis and Specialisation for the C Programming Language (C編程語言的程序分析和范圍限定)"中描述了指向分析。然而,不必使用指向分析,可使用計算每一指針可指向的對象的集合的任 何合適的方法。
例如,指向分析是域不敏感的而非基于域的(即,它不在結(jié)構(gòu)、聯(lián)合或類 中的不同域之間進行區(qū)分)。這種分析對所有源文件進行全局遍歷以收集子集 約束。每一分派x-;;導(dǎo)致子集約束;c2"這意味著x的可能值的集合包含y的
可能值的集合。該分析使用編譯器將每一源文件編譯成高層中間表示(HIR), 且它將HIR中的所有子集約束寫到文件。在該全局遍歷之后,它通過迭代所有 約束直到到達固定點來計算指向集合。然而,它將該指向集合存儲在文件中。
在全局遍歷期間,也收集寫可能在其他函數(shù)中讀取的位置的指令的標識 符。這包括寫入由解除引用(dereferencing)指針獲取的位置、靜態(tài)和全局變 量以及取得地址的本地變量。該信息也被寫到文件中。
使用指向集合和在全局遍歷期間收集到的分派來計算過程間到達定義。對 變量和臨時變量的使用,到達定義的集合是包含對該變量(或臨時變量)的所 有分派的標識符的集合與包含對可指向該變量(或臨時變量)的解除引用或指 針的所有分派的標識符的集合的并集。對指針解除引用,到達定義的集合是包 含對該解除引用的指針的所有分派的標識符的集合與該指針可指向的所有變 量的到達定義的集合的并集。過程間到達定義的集合被寫到用來操縱程序的文 件中。
在該示例中,過程內(nèi)和過程間分析均假設(shè)未定義存儲器中無關(guān)對象的相對 布局。它們假設(shè)正確的程序不會使用指針運算在存儲器中無關(guān)對象之間導(dǎo)航。
現(xiàn)有的編譯器在實現(xiàn)若干標準優(yōu)化時也采用這種假設(shè)。從而,這種假設(shè)適 用于絕大多數(shù)程序。然而,正是這種假設(shè)受到眾多攻擊的侵犯。數(shù)據(jù)流完整性 實施檢測并防止這些攻擊。
現(xiàn)在給出關(guān)于向軟件添加數(shù)據(jù)流跟蹤指令和數(shù)據(jù)流檢査指令的過程的更 多細節(jié)。
操縱
在特定示例中,通過將新的高級指令插入程序的高級中間表示來添加操 縱。例如,指令可具有以下形式 SETDEF opnd idCHECKDEF opnd setName.
注意到,不必對指令使用這種形式。可使用用于實現(xiàn)跟蹤數(shù)據(jù)流和檢查數(shù) 據(jù)流完整性的功能的任何合適形式的指令。
第一指令將叩nd (操作數(shù))的RDT入口設(shè)置為id。第二指令從RDT檢 索opnd的運行時定義標識符,并檢查該標識符是否位于具有名稱setName的 到達定義集合中。編譯器或其他合適的實體維護從集合名到集合值的映射,該 映射在將CHECKDEF指令降低為目標機器的匯編語言時使用。操縱代碼的高 級表示具有使操縱機器與源語言無關(guān)以及與目標體系結(jié)構(gòu)大部分無關(guān)的優(yōu)點。
以下是以上給出的示例代碼以及從由到達定義分析計算出的信息生成的 高級操縱的示例HIR。名稱為100的集合具有值{1,8}。在該示例中,不操縱可 確保被分派給寄存器的臨時變量,且也不操縱對&packet的使用,因為局部變 量的地址是通過向幀指針添加常量來計算的。 SETDEF—authenticated 1 —authenticated = ASSIGN 0 # 1
$L6:CHECKDEF —authenticated 100
t274 = CMP(NE) —authenticated, 0 #2 CBRANCH(NE) t274,$L7, $L8 #3 $L8:tv275 = CALL &—PacketRead, &_packet #4 t276 = CALL &_Authenticate, &_packet #5 t277 = CMP(NE) t276, 0 #6 CBRANCH(NE) t277,$L10, $L9 #7 $L 10: SETDEF —authenticated 8
—authenticated = ASSIGN 1 #8 $L9: GOTO $L6 #9
$L7:CHECKDEF —authenticated 100
t278 = CMP(NE) —authenticated, 0 #10 CBRANCH(NE) t278,$L12, $L11 #11 $112: tv279 = CALL &—ProcessPacket, &_packet #12 $L11:在描述任何將高級操縱降低為匯編語言之前,描述如何實現(xiàn)RDT。為了
允許高效的訪問,在一個示例中將RDT實現(xiàn)為具有所操縱程序中的每一 32位 的存儲器字的定義標識符的數(shù)組。每一定義標識符例如是二字節(jié)長的。這導(dǎo)致 約50%的空間開銷。
能夠?qū)γ恳?32位字記錄單個標識符,因為可生成其中沒有具有不同到達 定義集合的兩個變量共享相同對齊的32位存儲器字的代碼。由于我們的到達 定義分析不需在對象中的不同域中間以及數(shù)組中的不同元素之間進行區(qū)分,因 此沒有必要改變數(shù)組和對象的布局。僅改變編譯器以便在棧幀中布局局部變量 時使用32位的最小對齊。適當(dāng)對齊函數(shù)自變量、全局變量以及堆分派對象。
在特定示例中,向正在操縱的程序分派最低1GB的虛擬地址空間,并向 RDT分派512MB的虛擬地址空間,它們之間具有保護頁,即保護頁在地址 40000000h處,且RDT的基是在地址40001000h處的。因此為了計算操作數(shù)的 RDT入口的地址,僅將操作數(shù)的地址右移兩位,將結(jié)果乘以2,并加上 40001000h。該布局也允許對寫的目標地址的高效邊界檢查以防止篡改RDT。 在一個實現(xiàn)中,如果目標地扯與c0000000h的逐位AND為非零,則發(fā)生異常。 在另一實現(xiàn)中,使用位掩模來防止應(yīng)用程序?qū)慠DT。例如,可用3fffffffh來對 目標地址掩模以防止其引用RDT。保護頁允許僅檢查寫的目標地址并忽略大
高級操縱可降低為x86匯編語言,如以下示例所述。將SETDEF authenticated 1降低為
lea ecx, [_authenticated] test ecx, 0C0000000h je L int 3 L: shr ecx,2
movword ptr [ecx*2+4000 lOOOh], 1 第一指令將寫的目標地址加載到ecx,而隨后的三條指令對地址執(zhí)行邊界 檢查。如果檢査失敗,則當(dāng)前生成斷點(int3),這對于調(diào)試是非常方便的。另一異??赡芨m合生產(chǎn)使用。使用shr指令來計算—authenticated的RDT入 口的地址,mov指令更新入口。如果操作數(shù)的大小大于32位,則有必要更新 RDT中對應(yīng)于其他字的入口。可通過移動標識符的兩個副本的拼接來用單個 mov指令更新64位操作數(shù)的入口。但對于較大的操作數(shù),添加附加的指令。 CHEKCDEF authenticated 100指令被降低為
lea ecx, [—authenticated]
shr ecx,2
cmpword ptr [ecx*2+40001000h], 1 je L
cmpword ptr [ecx*2+40001000h],8 je L int 3
L:
該代碼對RDT入口中—authenticated的定義標識符與定義標識符集合100 進行比較。當(dāng)操作數(shù)大于32位時,對其他字添加附加的比較。
此外,操縱在編譯過程中引入的控制數(shù)據(jù)的定義和使用。例如對函數(shù)入口, 添加以下代碼以將對應(yīng)于函數(shù)的返回地址的RDT入口置為零 movecx, esp shr ecx,2
cmpword ptr [ecx*2+40001000h],0 je E int 3 L ret
回到以上涉及PacketRead和Authenticated的示例代碼片段,被操縱的代 碼不再易于受到重寫返回地址的控制數(shù)據(jù)攻擊以及重寫authenticated的非控制 數(shù)據(jù)攻擊。由于分析得出authenticated與packet未混疊的結(jié)論,對packet的寫 具有保證與1到8不同的標識符。另外,標識符零僅用于返回地址的函數(shù)入口。 從而,任何返回地址重寫也將被檢測出。
程序通常依賴于包括若干庫的復(fù)雜的運行時環(huán)境。通常不可能分析這些庫的源代碼。通常,僅庫可用,且即使在源代碼可用時,某些函數(shù)是用匯編語言 手寫的。然而,眾多攻擊利用庫中的易受攻擊性。例如,c庫中的串操縱函數(shù) 對于緩沖區(qū)溢出易受攻擊性而言是聲名狼藉的。
以往使用源代碼分析來操縱寫的技術(shù)無法提供任何保證,除非包裝庫調(diào)用 以執(zhí)行安全性檢查。這些以往的技術(shù)包括數(shù)組邊界檢査和C的存儲器安全語言 分支。有時,也要求包裝以執(zhí)行存儲器布局轉(zhuǎn)換。編寫這些包裝可能是麻煩的。
我們的數(shù)據(jù)流完整性實施方法可任選地不要求任何庫包裝。當(dāng)程序調(diào)用未 被分析的庫函數(shù)時,分析不能計算某些使用的到達定義集合,但是對所有其他 使用保證數(shù)據(jù)流的完整性。為此,操縱庫二進制代碼以便將它們所寫的任何存 儲器的RDT入口設(shè)置為無效定義標識符。這可在沒有源代碼的情況下完成。
提供定義庫包裝以增加覆蓋面的選擇。例如,定義庫函數(shù)的包裝,包括描 述調(diào)用函數(shù)添加到指向分析的子集約束以及編寫包裝函數(shù)。包裝檢查庫讀取的 存儲器的定義標識符、調(diào)用庫并為由庫所寫的存儲器設(shè)置定義標識符。操縱代 碼以調(diào)用包裝而非原始函數(shù),并向包裝提供庫函數(shù)所讀的存儲器的到達定義集
合以及它所寫的存儲器的定義標識符。例如,WindowNT TM操作系統(tǒng)調(diào)用 CreateProcess (創(chuàng)建進程)的包裝可檢查作為自變量提供的應(yīng)用程序名和命令 行串的完整性。
以下示出了 memcpy的示例包裝。CHECK—BOUNDS (檢査邊界)確保 memcpy不會寫到RDT,且CHECK_ARRAY (檢查數(shù)組)檢查RDT中用于scr 中字節(jié)的標識符是否位于defArgs中提供的到達定義集合中。寫到dest的字節(jié) 的RDT入口由UPDATE—RDT (更新RDT)置為defld。
void*
Dfi—memcpy(int* * defArgs, void *dest,
const void *src, size一t count)
unsigned int defld = (unsigned) defArgs [O]; CHECK—BOUNDS (dest, count); CHECK—ARRAY (defArgs,l,src,count);memcpy (dest, src, count); UPDATE—RDT(dest, count, defld); return dest;
優(yōu)化
我們的數(shù)據(jù)流完整性實施方法引入某些開銷每一定義引入對RDT的寫, 且每一使用檢查引入對RDT的讀繼之以針對該使用的到達定義集合中每一標 識符的比較。
開發(fā)了某些方法來減少這種開銷。它們歸入四種類型的方法。首先,可重 命名定義以減少CHECKDEF中比較的次數(shù),或允許要執(zhí)行的批量比較更為便 宜。其次,可使用靜態(tài)分析在保證移除某些SETDEF (設(shè)置定義)和SETDEF (檢查定義)不會損害數(shù)據(jù)流完整性時移除它們。最后,不同的定義可在運行 時以不同的頻率到達一使用??尚薷倪\行時系統(tǒng)來利用這種偏向。
重命名定義
第一種類型的優(yōu)化試圖重構(gòu)定義標識符空間,使得可將CHECKDEF編譯 成更高效的本機代碼。
開發(fā)了兩種技術(shù)。第一種技術(shù)按照允許對同一類中的所有定義分派同一標 識符的方式將定義分成等價類。如果兩個定義具有完全相同的使用集合,則它 們是等價的。這減少了 CHECKDEF中的比較次數(shù),以及表示標識符所需的位 數(shù)。例如,PacketRead示例中的—authenticated的兩個定義具有由靜態(tài)分析計算 出的同樣的使用集合。對這兩個定義分派同一標識符1。從而,CHECKDEF authenticated 100僅需一次比較。它被編譯成-
lea ecx, [—authenticated]
shr ecx,2
cmpword ptr [ecx*2+4000 lOOOh],l je Lint 3
L:
第二種類型的方法是重命名定義,以使得可使針對標識符集合的比較更 快。利用比較可采用不同的成本以不同方式執(zhí)行的事實。在一個實現(xiàn)中,有可 能有三種形式的比較(i)針對連續(xù)標識符O...n的范圍的檢査可由針對n的 單個無符號整數(shù)比較來實現(xiàn),(ii)針對連續(xù)標識符n...m的范圍的檢查可通 過減去n并執(zhí)行針對m-n的無符號比較來實現(xiàn),(iii)針對單個標識符n的檢 查可由普通的比較來實現(xiàn)。在其他實現(xiàn)中,存在可用各種成本執(zhí)行的不同或附 加形式的檢査。
將CHECKDEF的成本定義為執(zhí)行它所必需的減法和比較的次數(shù)。例如, 在示例實現(xiàn)中,檢査{1,3,7}的成本為三,但檢査{0,1,2}的成本僅為一。令標 識符集合的總成本為針對其的單個CHECKDEF的成本乘以在程序中發(fā)生的針 對其的CHECKDEF的次數(shù)。在示例實現(xiàn)中,使用對出現(xiàn)次數(shù)的靜態(tài)計數(shù)。本 領(lǐng)域的技術(shù)人員可以理解,其他實現(xiàn)可使用其他技術(shù),諸如估計所執(zhí)行的 CHECKDEF的次數(shù)的靜態(tài)試探法,或?qū)λ鶊?zhí)行的CHECKDEF計數(shù)或估計的 運行時反饋。
使用試探法來試圖減少所有集合的總成本的總和。特定的示例使用簡單的 貪婪算法按照遞減的總成本的次序?qū)吓判?,并進而將成本最高的集合分 派給連續(xù)的標識符范圍。從標識符0開始,因此具有最大總成本的集合受益于 最便宜的不計較。
移除邊界檢查
檢査寫的目標地址以防止攻擊者篡改RDT??赏ㄟ^從可靜態(tài)確定安全的 所有寫移除這些檢查來優(yōu)化SETDEF。在特定的示例中,如果目標地址是通過 將小常量偏移量(可能為0)加到棧指針、幀指針或全局或靜態(tài)變量的地址而 獲得的,則寫是安全的。優(yōu)選但并非必需地,偏移量與正在寫入的數(shù)據(jù)的大小 的總和小于4KB (這是在RDT之前所分派的保護頁的大小)。
例如,在PacketRead示例中,由于—authenticated是其地±止通過將小常量 加到幀指針來獲取的局部變量,因此可從SETDEF authenticatedl移除邊界檢 查。SETDEF被編譯成lea ecx, [—authenticated] shr ecx,2
movword ptr [ecx*2+40001000h],l 移除SETDEF和CHECKDEF
另一類型的優(yōu)化使用靜態(tài)分析來安全地移除某些SETDEF和 CHECKDEF 。
當(dāng)然,對我們所指的安全必須小心。存在兩個問題。首先,旨在不依賴于 其推斷在數(shù)據(jù)流完整性丟失時即不健全的高級分析操縱的整個目的是檢測程 序的數(shù)據(jù)流完整性受到損害的情況。其次,旨在不在編譯期間過早移除檢查, 因為稍后的代碼變換可能改變數(shù)據(jù)流完整性丟失的情況。從而,可任選地在 SETDEF和CHECKDEF操作仍以其HIR形式存在但程序的其余部分己經(jīng)被降 低成本機指令集且已經(jīng)發(fā)出時執(zhí)行我們的優(yōu)化。
第一種技術(shù)標識了在函數(shù)外沒有定義且僅通過安全寫入(根據(jù)之前章節(jié)中 對安全的定義)所寫的局部變量。它用置于函數(shù)入口上、帶有標識符O的單個 SETDEF替換這樣的變量的所有SETDEF。它也簡化這樣的變量的CHECKDEF 以具有等于{0}的到達定義集合。這種優(yōu)化是安全的,因為安全寫不會侵犯數(shù) 據(jù)流完整性。從而,僅有一個SETDEF是必需的。
第二種技術(shù)運行數(shù)據(jù)流分析以移除SETDEF和CHECKDEF。這種分析類 似于用來計算靜態(tài)數(shù)據(jù)流圖的到達定義分析,但它不依賴于可被攻擊者侵犯的 假設(shè)。為簡單起見,將在相同的基本塊內(nèi)描述指令序列的情況。這種技術(shù)也處 理任意控制流圖上跨不同基本塊傳播流變量的情況。
操縱在以下情況中是冗余的。假定指令I(lǐng)I和12是涉及在沒有對其的任何 介入寫的情況下執(zhí)行的同一數(shù)據(jù)的SETDEF或CHECKDEF對。
1. 如果I1和I2均為具有同樣的標識符的SETDEF,則I2是冗余的。
2. 如果II和12均是SETDEF,且未介入該數(shù)據(jù)的CHECKDEF,則II 是冗余的。
3. 如果II是IDl的SETDEF, 12是包含IDl的集合的CHECKDEF,則 12是冗余的(實際上,如果數(shù)據(jù)流分析正確地執(zhí)行,貝U IDl必定在12的集合中)。
4. 如果II和12分別是針對集合IDS1和IDS2的CHECKDEF,則IDS2 可被縮減以僅包含IDS1中的元素(早先的檢查保證不存在任何其他元素)。 而且,如果IDS1和IDS2持有同樣的元素,則12可被移除(如果早先的檢査 成功,則稍后的檢查不可能失敗)。
5. 如果II是針對集合IDS1的CHECKDEF,而12是針對ID2的SETDEF, 則當(dāng)IDS1^I2)時,12冗余。
在實踐中,規(guī)則3和4是最有效的。規(guī)則3在對數(shù)據(jù)的使用在其定義附近 發(fā)生時消除了眾多CHECKDEF指令。規(guī)則4令在重復(fù)使用同樣的數(shù)據(jù)時移除 CHECKDEF指令,即使在數(shù)據(jù)的定義以及這些使用中的第一個使用之間存在 混疊的寫。
為了標識冗余指令,使用以SEFDEF和CHECKDEF運算擴充的本機代碼 的符號執(zhí)行。在每一指令之后更新寄存器的符號狀態(tài),并在SETDEF和 CHECKDEF之后更新RDT的符號狀態(tài)。RDT的符號狀態(tài)將符號存儲器地址映 射到定義標識符的集合。
在一個示例中,使用簡單的測試來比較符號地址。如果兩個地址在句法上 是相等的,則它們是相等的。如果它們是通過將不同的偏移量加到相同的符號 寄存器狀態(tài)來計算的,則它們是不同的。否則,它們可能會引用混疊的存儲單 元。對存儲器的寫使寄存器的符號狀態(tài)無效,如果狀態(tài)引用可能與寫的目標混 疊的存儲單元的內(nèi)容。另外,它從符號RDT狀態(tài)中移除可能與寫的目標混疊
的任何存儲器的映射。
應(yīng)用這些規(guī)則來通過檢查符號RDT狀態(tài)消除冗余操縱。由于一次對單個 基本塊工作,在指令冗余時立即移除指令——這可容易地轉(zhuǎn)成塊間實現(xiàn)中的單 獨的輪次。
利用偏向的數(shù)據(jù)流
我們的最終技術(shù)基于不同的定義可在運行時以不同的頻率到達一使用的 預(yù)期。例如,在以下示例中,定義D1僅在循環(huán)上的第一次迭代時到達行3: 1: intx=…;〃D1 2: for (int y = 0; y < 100; y ++)3:x++; 〃D2 4:}
可任選地添加將地址映射到最近在它們處看到的定義標識符的第二全局 表。于是,對成本大于2的針對集合的任何CHECKDEF,通過針對表中所保 存的值的比較來繼續(xù)檢查。如果它匹配,則保證檢査成功。如果它失敗,則更 新表并繼續(xù)檢查。
或者,可使用概況信息來對成員檢查重新排序,從而首先執(zhí)行對更頻繁到 達使用的定義標識符的檢査。概況信息可在程序的概況運行期間收集,而檢査 可在編譯程序時重新排序。或者,概況信息可在程序的正常運行期間收集,而 檢査可在程序運行時動態(tài)重新排序。
本領(lǐng)域的技術(shù)人員將認識到用于存儲程序指令的存儲設(shè)備可分布在網(wǎng)絡(luò) 上。例如,遠程計算機可存儲描述為軟件的該過程的示例。本地或終端計算機 可訪問遠程計算機并下載該軟件的一部分或全部以運行該程序?;蛘?,本地計 算機可按需下載軟件的片斷,或可以在本地終端處執(zhí)行一些軟件指令而在遠程 計算機(或計算機網(wǎng)絡(luò))處執(zhí)行一些軟件指令。本領(lǐng)域的技術(shù)人員將認識到,
通過使用本領(lǐng)域技術(shù)人員已知的常規(guī)技術(shù),軟件指令的全部或部分可由專用電 路,如DSP、可編程邏輯陣列等來執(zhí)行。
如本領(lǐng)域的技術(shù)人員將清楚的,此處給出的任何范圍或者設(shè)備值都可以被 擴展或者改變而不失去所尋求的效果。
本文中描述的各方法步驟可以在適當(dāng)時按任何合適的次序或同時執(zhí)行。 可以理解,上面對于較佳實施例的描述僅僅是作為示例給出的,而本領(lǐng)域 的技術(shù)人員可以做出各種修改。以上說明、示例和數(shù)據(jù)提供了對本發(fā)明的各示 例性實施例的結(jié)構(gòu)和使用的全面描述。盡管以上帶著一定程度的特殊性或?qū)σ?個或多個單獨實施例的參考描述了本發(fā)明的各實施例,但是本領(lǐng)域的技術(shù)人員 能夠?qū)λ_的實施例做出多種更改而不背離本發(fā)明的精神或范圍。
權(quán)利要求
1. 一種方法,包括(i)提供對軟件程序的靜態(tài)分析的結(jié)果的訪問,所述靜態(tài)分析結(jié)果包括數(shù)據(jù)流信息;(ii)形成數(shù)據(jù)流跟蹤指令以便跟蹤所述軟件內(nèi)的數(shù)據(jù)流;以及(iii)形成檢查指令以針對所述靜態(tài)分析結(jié)果檢查所跟蹤的數(shù)據(jù)流并從而標識所述軟件程序中的潛在缺陷。
2. 如權(quán)利要求1所述的方法,其特征在于,所述數(shù)據(jù)流跟蹤指令和檢査指 令使用修改的編譯器(52)或二進制重寫工具(62)中的任何一個形成并添加 到所述軟件。
3. 如權(quán)利要求1所述的方法,其特征在于,所述數(shù)據(jù)流跟蹤指令和所述檢查指令是使用被安排成仿真執(zhí)行所述軟件程序的處理器的機器仿真程序和所 述機器仿真程序的硬件等價物中的任何一個實現(xiàn)的。
4. 如前述權(quán)利要求中任一項所述的方法,其特征在于,所述潛在缺陷包括 控制數(shù)據(jù)攻擊和非控制數(shù)據(jù)攻擊兩者。
5. 如前述權(quán)利要求中任一項所述的方法,其特征在于,對由所述軟件程序 中的指令讀取的每一值,所述靜態(tài)分析結(jié)果包括來自所述軟件程序中可寫所述 值的指令的集合。
6. 如前述權(quán)利要求中任一項所述的方法,其特征在于,還包括通過根據(jù)所 述軟件程序的源代碼計算到達定義來執(zhí)行對所述軟件程序的靜態(tài)分析。
7. 如前述權(quán)利要求中任一項所述的方法,其特征在于,所述數(shù)據(jù)流跟蹤指 令被安排成在標識符和存儲器位置之間維護映射,所述標識符是對寫入所述每一存儲器位置的最后一條指令的標識符。
8. 如前述權(quán)利要求中任一項所述的方法,其特征在于,檢査指令與讀指令 相關(guān)聯(lián)。
9. 如權(quán)利要求6所述的方法,其特征在于,與讀指令相關(guān)聯(lián)的檢查指令被安排成檢查寫正由授權(quán)的讀指令讀取的值的指令的標識符是否是由所述靜態(tài) 分析計算出的相關(guān)聯(lián)集合中的元素。
10. 如權(quán)利要求5所述的方法,其特征在于,還包括確定指令的等價類, 并向同一類中的所有指令分派同一標識符。
11. 如前述權(quán)利要求中任一項所述的方法,其特征在于,還包括基于第 二靜態(tài)分析移除某些數(shù)據(jù)流跟蹤指令和某些檢査指令。
12. 如前述權(quán)利要求中任一項所述的方法,其特征在于,還包括通過計 算到達定義并重命名這些到達定義中的至少某些來執(zhí)行對所述軟件程序的靜 態(tài)分析,以便改善針對這些到達定義進行檢査的過程的性能。
13. —種方法,包括(i) 訪問軟件程序的靜態(tài)分析的結(jié)果,所述靜態(tài)分析結(jié)果包括數(shù)據(jù)流信息;(ii) 在所述軟件程序的執(zhí)行或仿真期間跟蹤所述軟件程序中的數(shù)據(jù)流;以及(iii) 針對所述靜態(tài)分析結(jié)果檢査所跟蹤的數(shù)據(jù)流,且如果找到失配則發(fā) 生異常。
14. 一種包括計算機程序代碼裝置的計算機程序,所述代碼裝置適于當(dāng) 所述程序在計算機上運行時執(zhí)行前述權(quán)利要求中任一項的所有步驟。
15. 如權(quán)利要求14所述的計算機程序,其特征在于,所述計算機程序被包含在計算機可讀介質(zhì)上。
16. —種裝置(52、 62、 70),包括(i) 被安排成訪問對軟件程序的靜態(tài)分析(61)的結(jié)果的輸入,所述靜 態(tài)分析結(jié)果包括數(shù)據(jù)流信息;(ii) 被安排成形成數(shù)據(jù)流跟蹤指令以便跟蹤所述軟件內(nèi)的數(shù)據(jù)流的處理 器(54);以及(iii) 被安排成形成檢查指令以針對所述靜態(tài)分析結(jié)果檢查所跟蹤的數(shù)據(jù) 流并從而標識所述軟件程序中的潛在缺陷的處理器(54)。
17. 如權(quán)利要求16所述的裝置,其特征在于,還包括被安排成通過根 據(jù)所述軟件程序的源代碼計算到達定義來執(zhí)行對所述軟件程序的靜態(tài)分析的 編譯器(52)。
18. 如權(quán)利要求16或權(quán)利要求17所述的裝置,其特征在于,所述處理 器(54)被配置成形成數(shù)據(jù)流跟蹤指令以維護標識符和存儲器位置之間的映射, 所述標識符是寫入每一存儲器位置的最后一條指令的標識符。
19. 如權(quán)利要求18所述的裝置,其特征在于,所述處理器被安排成對 每一讀指令形成所述檢查指令,來檢査寫正在讀取值的指令的標識符是否是所 述靜態(tài)分析所計算出的相關(guān)聯(lián)集合中的元素。
20. —種裝置,包括(i) 被安排成訪問對軟件程序的靜態(tài)分析(61)的結(jié)果的輸入,所述靜 態(tài)分析結(jié)果包括數(shù)據(jù)流信息;(ii) 被安排成在所述軟件程序執(zhí)行或仿真期間跟蹤所述軟件程序中的數(shù) 據(jù)流的處理器(54);以及(iii)其中所述處理器(54)還被安排成針對所述靜態(tài)分析結(jié)果檢査所跟 蹤的數(shù)據(jù)流,且如果找到失配則發(fā)出異常。
全文摘要
大多數(shù)這樣的軟件攻擊利用軟件易受攻擊性或缺陷將數(shù)據(jù)編寫到非預(yù)期的位置中。例如,控制數(shù)據(jù)攻擊利用緩沖區(qū)溢出或其他易受攻擊性來重寫棧中的返回地址、函數(shù)指針或某些其他控制數(shù)據(jù)。非控制數(shù)據(jù)攻擊利用類似的易受攻擊性來重寫安全關(guān)鍵數(shù)據(jù)而不會破壞程序中的預(yù)期控制流。描述用于針對控制數(shù)據(jù)和非控制數(shù)據(jù)攻擊兩者來保護軟件的方法。執(zhí)行靜態(tài)分析以確定軟件程序的數(shù)據(jù)流信息。形成數(shù)據(jù)流跟蹤指令以便在該軟件的執(zhí)行或仿真期間跟蹤數(shù)據(jù)流。而且,形成檢查指令以針對靜態(tài)分析結(jié)果檢查所跟蹤的數(shù)據(jù)流并從而標識潛在的攻擊或錯誤。描述可任選的優(yōu)化來減少產(chǎn)生的額外開銷。
文檔編號G06F21/52GK101473300SQ200780023352
公開日2009年7月1日 申請日期2007年5月4日 優(yōu)先權(quán)日2006年6月23日
發(fā)明者M·卡斯特羅, M·科斯塔, T·哈里斯 申請人:微軟公司