VC的Buffer Security Check

        C/C++對內存的訪問非常自由,也會帶來一些問題。比如對一個局部數組變量的越界寫入就可能導致棧數據被意外修改。

        爲了防止線程棧被有意無意錯誤改寫,VC編譯器提供了/GS開關,指示編譯器在棧的某些變量的前後留出空白內存區。編譯器在原函數體代碼前面插入代碼,向空白內存區中寫入某個數值(security cookie),並在原函數體代碼後面插入代碼檢查空白內存區中的數值是否保持不變。如果發生了變化,則報異常。這被稱爲Buffer Security Check。

       所有符合下面條件的局部變量會受到這一措施的保護:

  1. An array that is larger than 4 bytes, has more than two elements,and has an element type that is not a pointer type.
  2. A data structure whose size is more than 8 bytes and contains nopointers.
  3. A buffer allocated by using the _allocafunction.
  4. Any class or structure that contains a GS buffer.

      比如,以下變量是符合條件的:

  • char buffer[20];
  • int buffer[20];
  • struct { int a; int b; int c; int d; } myStruct;
  • struct { int a; char buf[20]; };

      比如,以下是不符合條件的(x86平臺下),不會生成security cookies:

  • char *pBuf[20];
  • void *pv[20];
  • char buf[4];
  • int buf[2];
  • struct { int a; int b; };

      打開GS開關後,有較大可能性檢查到棧內存的非法寫入,顯然這也不是百分之百的保證。在VS2012下面,不管是Debug還是Release,GS開關默認都是被打開的。

 

測試程序

#include <cstring>
#include <stdlib.h>

// Vulnerable function
void vulnerable(const char *str) {
	char buffer[10] = "abcdefg";
	int i = 0;
	char buffer2[20] = "ABCDEFGHIJKLMN";
	int k = 30;
	int l = 50;
	for( i = 0 ; i < 10; i++)
		buffer[i] = '0' + i;
	for( k = 0 ; k < 20; k++)
		buffer2[k] = '0' + i;
}

int main() {
   char large_buffer[] = "";
   vulnerable(large_buffer);
}

        下面利用VC的調試功能,對vulnerable函數進行棧分析。下圖是運行到vulnerable函數的時候,VC調試器的截圖。其中標註了棧頂指針的值、各個局部變量的位置和值。可以看到每個buffer數組的前後都分配了一組"CC"作爲隔離帶,而變量k和l之間沒有隔離帶。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章