什么是整數溢出?溢出方式(回繞,截斷),表現,危害


一:什么是整數溢出

      由於整數在內存里面保存在一個固定長度的空間內,它能存儲的最大值和最小值是固定的,如果我們嘗試去存儲一個數,而這個數又大於這個固定的最大值時,就會導致整數溢出。(x86-32 的數據模型是 ILP32,即整數(Int)、長整數(Long)和指針(Pointer)都是 32 位。)

二、溢出類型及表現

1.溢出

只有符號的數才會發生溢出

對於signed整型的溢出,C的規范定義是“undefined behavior”,也就是說,編譯器愛怎么實現就怎么實現。對於大多數編譯器來說,仍然是回繞。

2.回繞

無符號數會回繞(常繞過一些判斷語句)

對於unsigned整型溢出,C的規范是有定義的——“溢出后的數會以2^(8*sizeof(type))作模運算”,也就是說,如果一個unsigned char(1字符,8bits)溢出了,會把溢出的值與256求模。例如:

1
2
unsigned  char  x = 0xff;
printf ( "%d\n" , ++x);

上面的代碼會輸出:0 (因為0xff + 1是256,與2^8求模后就是0)

3.截斷

將一個較大寬度的數存入一個寬度小的操作數中,高位發生截斷

三、簡單了解整數溢出的危害

      1. 整數回繞之后,會導致索引越界,取到不確定的數據

  2. 或者判斷失效,形成死循環。

  3. 回繞之后,導致分配超大內存。

四、Keil將變量加入Watch后,如果溢出顯示的值后會帶個“?”號

觀察到這種情況就要注意了。

 

五、例子

第一種情況——有符合號溢出舉個例子:


int i;

i = INT_MAX; // 2 147 483 647

i++; printf("i = %d\n", i); // i = -2 147 483 648

第二種情況——無符號回繞舉個列子:


unsigned int ui;

ui = UINT_MAX; // 在 x86-32 上為 4 294 967 295 ui++;

printf("ui = %u\n", ui); // ui = 0

ui = 0;

ui--; printf("ui = %u\n", ui); // 在 x86-32 上,ui = 4 294 967 295

第三種情況——高位截斷截斷舉倆例子:


加法截斷:

0xffffffff + 0x00000001

= 0x0000000100000000 (long long)

= 0x00000000 (long)

乘法截斷:

0x00123456 * 0x00654321

= 0x000007336BF94116 (long long)

= 0x6BF94116 (long)

漏洞多發函數

1.*memcpy(void *dest, const void *src, size_t n)函數

2.*strncpy(char *dest,const char *scr, size_t n)函數

ps說明:其中參數n,是size_t類型,size_t是一個無符號整型的類型

 

C語言源碼示例:

示例一:


char buf[80];

void vulnerable() {

int len = read_int_from_network();
char *p = read_string_from_network();
if (len > 80) {
   error("length too large: bad dog, no cookie for you!");
   return;
}
memcpy(buf, p, len);

}

當給len賦值為復數時,可繞過if判斷,因為memcpy()函數中 的len是size_t類型會把復數len轉換為整數,當len被賦值后絕對值很大時就會復制大量的內容到buf中,發生溢出

示例二:


void vulnerable() {

size_t len;
// int len;
char* buf;

len = read_int_from_network();
buf = malloc(len + 5);
read(fd, buf, len);
...

}

這個例子看似避開了緩沖區溢出的問題,但是如果 len 過大,len+5 有可能發生回繞。比如說,在 x86-32 上,如果 len = 0xFFFFFFFF,則 len+5 = 0x00000004,這時 malloc() 只分配了 4 字節的內存區域,然后在里面寫入大量的數據,緩沖區溢出也就發生了。(如果將 len 聲明為有符號 int 類型,len+5 可能發生溢出)

示例三:


void main(int argc, char *argv[]) {

unsigned short int total;
total = strlen(argv[1]) + strlen(argv[2]) + 1;
char *buf = (char *)malloc(total);
strcpy(buf, argv[1]);
strcat(buf, argv[2]);
...

}

這個例子接受兩個字符串類型的參數並計算它們的總長度,程序分配足夠的內存來存儲拼接后的字符串。首先將第一個字符串參數復制到緩沖區中,然后將第二個參數連接到尾部。如果攻擊者提供的兩個字符串總長度無法用 total 表示,則會發生截斷,從而導致后面的緩沖區溢出。

 

C語言的整型溢出問題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM