/GS (緩衝區安全性檢查)
偵測某些緩衝區滿溢,覆寫函式的傳回位址、例外狀況處理程式位址或特定類型的參數。 造成緩衝區滿溢是駭客用來利用不強制執行緩衝區大小限制的程式代碼的技術。
語法
/GS[-]
備註
/GS 預設為開啟。 如果您預期應用程式沒有安全性風險,請使用 /GS-。 如需隱藏緩衝區滿溢偵測的詳細資訊,請參閱 安全緩衝器。
安全性檢查
在編譯程式辨識為受緩衝區滿溢問題的函式上,編譯程式會在傳回位址之前,在堆棧上配置空間。 在函式專案上,配置的空間會以模組載入時計算一 次的安全性 Cookie 來載入。 在函式結束時,以及在64位操作系統的框架回溯期間,會呼叫協助程式函式,以確保Cookie的值仍然相同。 不同的值表示可能已經覆寫堆疊。 如果偵測到不同的值,就會終止進程。
GS 緩衝區
緩衝區滿溢安全性檢查是在 GS 緩衝區上執行。 GS 緩衝區可以是下列其中一項:
大於 4 個字節的陣列,具有兩個以上的元素,而且具有不是指標類型的項目類型。
大小超過8個字節且不包含指標的數據結構。
使用 _alloca 函式配置的緩衝區。
包含 GS 緩衝區的任何類別或結構。
例如,下列語句會宣告 GS 緩衝區。
char buffer[20];
int buffer[20];
struct { int a; int b; int c; int d; } myStruct;
struct { int a; char buf[20]; };
不過,下列語句不會宣告 GS 緩衝區。 前兩個宣告包含指標類型的元素。 第三個和第四個語句會宣告大小太小的陣列。 第五個語句會宣告在 x86 平臺上的大小不超過 8 個字節的結構。
char *pBuf[20];
void *pv[20];
char buf[4];
int buf[2];
struct { int a; int b; };
初始化安全性 Cookie
/GS 編譯程式選項會要求在執行任何使用Cookie的函式之前,先初始化安全性Cookie。 安全性 Cookie 必須在 EXE 或 DLL 的專案上立即初始化。 如果您使用預設的 VCRuntime 進入點:mainCRTStartup、wmainCRTStartup、WinMainCRTStartup、wWinMainCRTStartup 或 _DllMainCRTStartup,就會自動完成此動作。 如果您使用替代進入點,您必須呼叫 __security_init_cookie手動初始化安全性 Cookie。
什麼是受保護的
/GS 編譯程式選項會保護下列專案:
函數調用的傳回位址。
函式的例外狀況處理程式位址。
易受攻擊的函式參數。
在所有平臺上, /GS 會嘗試偵測傳回位址中的緩衝區滿溢。 緩衝區滿溢在 x86 和 x64 等平臺上更容易被利用,其使用呼叫慣例來儲存堆疊上函式呼叫的傳回位址。
在 x86 上,如果函式使用例外狀況處理程式,編譯程式會插入安全性 Cookie 來保護例外狀況處理程序的位址。 在框架回溯期間,會檢查 Cookie。
/GS 會 保護傳遞至函式的易受攻擊參數 。 易受攻擊的參數是指針、C++參考、包含指標或 GS 緩衝區的 C 結構(C++ POD 類型)。
易受攻擊的參數會在 Cookie 和局部變數之前配置。 緩衝區滿溢可以覆寫這些參數。 而使用這些參數的函式中的程式代碼可能會在函式傳回並執行安全性檢查之前造成攻擊。 為了將這種危險降到最低,編譯程式會在函式初構期間製作易受攻擊參數的複本,並將其置於任何緩衝區的儲存區域下方。
在下列情況下,編譯程式不會複製易受攻擊的參數:
不包含 GS 緩衝區的函式。
未啟用優化 (/O 選項)。
具有變數自變數清單的函式 (...)。
以 裸體標示的函式。
在第一個語句中包含內嵌元件程式代碼的函式。
只有在緩衝區滿溢時,參數才會以不太可能被利用的方式使用。
未受到保護的內容
/GS 編譯程序選項不會防範所有緩衝區超支安全性攻擊。 例如,如果您的物件中有緩衝區和 vtable,緩衝區滿溢可能會損毀 vtable。
即使您使用 /GS,也一律嘗試撰寫沒有緩衝區滿溢的安全程序代碼。
在 Visual Studio 中設定這個編譯器選項
開啟專案的 [屬性頁] 對話方塊。 如需詳細資料,請參閱在 Visual Studio 中設定 C ++ 編譯器和組建屬性。
選取 [組態屬性>C/C++>Code 產生] 屬性頁。
修改 Buffer Security Check 屬性。
若要以程式方式設定這個編譯器選項
- 請參閱 BufferSecurityCheck。
範例
此範例會滿溢緩衝區。 這會導致應用程式在運行時間失敗。
// compile with: /c /W1
#include <cstring>
#include <stdlib.h>
#pragma warning(disable : 4996) // for strcpy use
// Vulnerable function
void vulnerable(const char *str) {
char buffer[10];
strcpy(buffer, str); // overrun buffer !!!
// use a secure CRT function to help prevent buffer overruns
// truncate string to fit a 10 byte buffer
// strncpy_s(buffer, _countof(buffer), str, _TRUNCATE);
}
int main() {
// declare buffer that is bigger than expected
char large_buffer[] = "This string is longer than 10 characters!!";
vulnerable(large_buffer);
}