1. 程式人生 > >c語言strcpy函式的漏洞

c語言strcpy函式的漏洞

    函式裡的區域性變數一般都是按序排放的,並且因為是分配在堆疊之中,它們的地址是向下“增長”,即向低地址方向增長。比如下面的程式:

   int flag=0x12345678;
   printf("%x\n",flag);

   char s[6];
   printf("address of  flag:   %x\n",&flag);
   printf("address of array s: %x\n",s);
   strcpy(s,"my aaaa");

   printf("%s\n",s);
   printf("%x\n",flag);
   printf("%c\n",*(char *)(&flag));//輸出變數flag的第一個位元組的內容

上面的程式申明瞭一個變數flag並初始化為十六進位制的12345678,以及一個字元型陣列s。程式的執行結果如下圖:


從圖中可以看出,程式執行時把變數flag分配的地址是0x28ff1c,而字元陣列s的地址為0x28ff16,可以看到地址的增長方向是向下的,同時,s相對於flag的偏移量正好是字元陣列s的大小,即6。在執行函式strcpy之前,可以把它們在記憶體中的佈局表示如下(以位元組為單位):


因為我的機器中,資料的位元組序是小端模式(小端模式即是:資料的高位儲存在記憶體的高地址,而地位儲存在記憶體的低地址,大端模式倒過來的),所以對於變數flag,其高位為0x12儲存在最高地址處,而其低位的0x78儲存在其變數的起始處。

這樣的話,當執行函式strcpy(s,"my aaaa")時,它會將從0x28ff16的地址處向上的連續的8個位元組分別賦值為字串“my aaaa”的每個字元(第8個位元組是函式strcpy加上的一個字串終止符0x00)。那麼此時的記憶體情況如下:


可以看到,執行strcpy函式時,它會將變數flag的前兩個位元組也改寫了!(圖中紅色的表示被改寫的,即flag的第一個位元組被重新賦值為了字元‘a’,第二個位元組被賦值為終止符0x00)。為什麼會這樣?因為strcpy函式並不檢查目的緩衝區的大小邊界,而是將源字串逐一的全部賦值給目的字串地址起始的一塊連續的記憶體空間,同時加上字串終止符

所以最後輸出變數flag時,其值變為0x12340061,即其高兩位元組未變,而最低位變為0x61即97,即字元a的ascii碼,第二低位元組變為0x00,即字串終止符。

所以,使用strcpy時容易出錯,不幸的是,這種bug是不易被發現的。所以需要格外的小心。為了避免出錯,可以使用另一個具有相同功能的函式: strncpy,該函式可以指定要複製的字串的長度。