A. c語言程序輸出數據溢出問題
在c語言中,數據的存儲就像一個圓圈,正數溢出數據就會從最小負數開始,負數溢出數據同理,打個比方(簡略寫一下):
int
a=32768,b=-32769;
printf("a=%d,b=%d",&a,&b);
則會輸出a=-32768,b=32767;
這樣則50000輸出就是(50000-32767)+(-32768)+(-1)=-15536
B. c語言算術溢出問題怎麼解決
首先,這是警告,告訴你有可能產生溢出風險,並不是一定會發生溢出。
其次,底下已經告訴你了,要強制轉換一下……
sqrt(i+(long int)100);
C. c語言數據溢出怎麼辦
C語言的強大之處就在於他的靈活性,程序員自己把握。編譯器可以幫助預防錯誤,但有些程序會利用溢出,所以溢出不完全是錯誤的事情。
1、溢出:
數據類型超過了計算機字長的界限而出現的數據溢出;
2、溢出可能原因:
當應用程序讀取用戶數據,復制到應用程序開辟的內存緩沖區中,卻無法保證緩沖區的空間足夠時 (假設定義數組int Array[10], 而在調用時使用Array[11] 或存放的數據超過int類型容量等), 內存緩沖區就可能會溢出.
3、溢出因素分析:
由於C/C++語言所固有的缺陷,既不檢查數組邊界,又不檢查類型可靠性,且用C/C++語言開發的程序由於目標代碼非常接近機器內核,因而能夠直接訪問內存和寄存器,只要合理編碼,C/C++應用程序在執行效率上必然優於其它高級語言。然而,C/C++語言導致內存溢出問題的可能性也要大許多。
D. c語言中數據溢出的問題怎麼解決
需要准備的材料分別有:電腦、C語言編譯器。
1、首先,打開C語言編譯器,新建一個初始.cpp文件,例如:test.cpp,輸入問題基礎代碼。
E. 什麼是C語言緩沖區溢出漏洞怎麼利用誰可以提供詳細的資料
緩沖區溢出漏洞入門介紹
文/hokersome
一、引言
不管你是否相信,幾十年來,緩沖區溢出一直引起許多嚴重的安全性問題。甚至毫不誇張的說,當前網路種種安全問題至少有50%源自緩沖區溢出的問題。遠的不說,一個沖擊波病毒已經令人談溢出色變了。而作為一名黑客,了解緩沖區溢出漏洞則是一門必修課。網上關於溢出的漏洞的文章有很多,但是大多太深或者集中在一個主題,不適合初學者做一般性了解。為此,我寫了這篇文章,主要是針對初學者,對緩沖區溢出漏洞進行一般性的介紹。
緩沖區溢出漏洞是之所以這么多,是在於它的產生是如此的簡單。只要C/C++程序員稍微放鬆警惕,他的代碼裡面可能就出現了一個緩沖區溢出漏洞,甚至即使經過仔細檢查的代碼,也會存在緩沖區溢出漏洞。
二、溢出
聽我說了這些廢話,你一定很想知道究竟什麼緩沖區溢出漏洞,溢出究竟是怎麼發生的。好,現在我們來先弄清楚什麼是溢出。以下的我將假設你對C語言編程有一點了解,一點點就夠了,當然,越多越好。
盡管緩沖區溢出也會發生在非C/C++語言上,但考慮到各種語言的運用程度,我們可以在某種程度上說,緩沖區溢出是C/C++的專利。相信我,如果你在一個用VB寫的程序裡面找溢出漏洞,你將會很出名。回到說C/C++,在這兩種使用非常廣泛的語言裡面,並沒有邊界來檢查數組和指針的引用,這樣做的目的是為了提高效率,而不幸的是,這也留下了嚴重的安全問題。先看下面一段簡單的代碼:
#include<stdio.h>
void main()
{
char buf[8];
gets(buf);
}
程序運行的時候,如果你輸入「Hello」,或者「Kitty」,那麼一切正常,但是如果輸入「Today is a good day」,那麼我得通知你,程序發生溢出了。很顯然,buf這個數組只申請到8個位元組的內存空間,而輸入的字元卻超過了這個數目,於是,多餘的字元將會佔領程序中不屬於自己的內存。因為C/C++語言並不檢查邊界,於是,程序將看似正常繼續運行。如果被溢出部分佔領的內存並不重要,或者是一塊沒有使用的內存,那麼,程序將會繼續看似正常的運行到結束。但是,如果溢出部分佔領的正好的是存放了程序重要數據的內存,那麼一切將會不堪設想。
實際上,緩沖區溢出通常有兩種,堆溢出和堆棧溢出。盡管兩者實質都是一樣,但由於利用的方式不同,我將在下面分開介紹。不過在介紹之前,還是來做一些必要的知識預備。
三、知識預備
要理解大多數緩沖區溢出的本質,首先需要理解當程序運行時機器中的內存是如何分配的。在許多系統上,每個進程都有其自己的虛擬地址空間,它們以某種方式映射到實際內存。我們不必關心描述用來將虛擬地址空間映射成基本體系結構的確切機制,而只關心理論上允許定址大塊連續內存的進程。
程序運行時,其內存裡面一般都包含這些部分:1)程序參數和程序環境;2)程序堆棧,它通常在程序執行時增長,一般情況下,它向下朝堆增長。3)堆,它也在程序執行時增長,相反,它向上朝堆棧增長;4)BSS 段,它包含未初始化的全局可用的數據(例如,全局變數); 5)數據段,它包含初始化的全局可用的數據(通常是全局變數);6)文本段,它包含只讀程序代碼。BSS、數據和文本段組成靜態內存:在程序運行之前這些段的大小已經固定。程序運行時雖然可以更改個別變數,但不能將數據分配到這些段中。下面以一個簡單的例子來說明以上的看起來讓人頭暈的東西:
#include<stdio.h>
char buf[3]="abc";
int i;
void main()
{
i=1
return;
}
其中,i屬於BBS段,而buf屬於數據段。兩者都屬於靜態內存,因為他們在程序中雖然可以改變值,但是其分配的內存大小是固定的,如buf的數據大於三個字元,將會覆蓋其他數據。
與靜態內存形成對比,堆和堆棧是動態的,可以在程序運行的時候改變大小。堆的程序員介面因語言而異。在C語言中,堆是經由 malloc() 和其它相關函數來訪問的,而C++中的new運算符則是堆的程序員介面。堆棧則比較特殊,主要是在調用函數時來保存現場,以便函數返回之後能繼續運行。
四、堆溢出
堆溢出的思路很簡單,覆蓋重要的變數以達到自己的目的。而在實際操作的時候,這顯得比較困難,尤其是源代碼不可見的時候。第一,你必須確定哪個變數是重要的變數;第二,你必須找到一個內存地址比目標變數低的溢出點;第三,在特定目的下,你還必須讓在為了覆蓋目標變數而在中途覆蓋了其他變數之後,程序依然能運行下去。下面以一個源代碼看見的程序來舉例演示一次簡單的堆溢出是如何發生的:
#include "malloc.h"
#include "string.h"
#include "stdio.h"
void main()
{
char *large_str = (char *)malloc(sizeof(char)*1024);
char *important = (char *)malloc(sizeof(char)*6);
char *str = (char *)malloc(sizeof(char)*4);
strcpy(important,"abcdef");//給important賦初值
//下面兩行代碼是為了看str和important的地址
printf("%d/n",str);
printf("%d/n",important);
gets(large_str);//輸入一個字元串
strcpy(str, large_str);//代碼本意是將輸入的字元串拷貝到str
printf("%s/n",important);
}
在實際應用中,這樣的代碼當然是不存在的,這只是一個最簡單的實驗程序。現在我們的目標是important這個字元串變成"hacker"。str和important的地址在不同的環境中並不是一定的,我這里是7868032和7868080。很好,important的地址比str大,這就為溢出創造了可能。計算一下可以知道,兩者中間隔了48個位元組,因此在輸入溢出字元串時候,可以先輸入48個任意字元,然後再輸入hakcer回車,哈哈,出來了,important成了"hacker"。
五、堆棧溢出
堆溢出的一個關鍵問題是很難找到所謂的重要變數,而堆棧溢出則不存在這個問題,因為它將覆蓋一個非常重要的東西----函數的返回地址。在進行函數調用的時候,斷點或者說返回地址將保存到堆棧裡面,以便函數結束之後繼續運行。而堆棧溢出的思路就是在函數裡面找到一個溢出點,把堆棧裡面的返回地址覆蓋,替換成一個自己指定的地方,而在那個地方,我們將把一些精心設計了的攻擊代碼。由於攻擊代碼的編寫需要一些匯編知識,這里我將不打算涉及。我們這里的目標是寫出一個通過覆蓋堆棧返回地址而讓程序執行到另一個函數的堆棧溢出演示程序。
因為堆棧是往下增加的,因此,先進入堆棧的地址反而要大,這為在函數中找到溢出點提供了可能。試想,而堆棧是往上增加的,我們將永遠無法在函數裡面找到一個溢出點去覆蓋返回地址。還是先從一個最簡單的例子開始:
void test(int i)
{
char buf[12];
}
void main()
{
test(1);
}
test 函數具有一個局部參數和一個靜態分配的緩沖區。為了查看這兩個變數所在的內存地址(彼此相對的地址),我們將對代碼略作修改:
void test(int i)
{
char buf[12];
printf("&i = %d/n", &i);
printf("&buf[0] = %d/n", buf);
}
void main()
{
test(1);
}
需要說明的是,由於個人習慣的原因,我把地址結果輸出成10進制形式,但願這並不影響文章的敘述。在我這里,產生下列輸出:&i = 6684072 &buf[0] = 6684052。這里我補充一下,當調用一個函數的時候,首先是參數入棧,然後是返回地址。並且,這些數據都是倒著表示的,因為返回地址是4個位元組,所以可以知道,返回地址應該是保存在從6684068到6684071。因為數據是倒著表示的,所以實際上返回地址就是:buf[19]*256*256*256+buf[18]*256*256+buf[17]*256+buf[16]。
我們的目標還沒有達到,下面我們繼續。在上面程序的基礎,修改成:
#include <stdio.h>
void main()
{
void test(int i);
test(1);
}
void test(int i)
{
void come();
char buf[12];//用於發生溢出的數組
int addr[4];
int k=(int)&i-(int)buf;//計算參數到溢出數組之間的距離
int go=(int)&come;
//由於EIP地址是倒著表示的,所以首先把come()函數的地址分離成位元組
addr[0]=(go << 24)>>24;
addr[1]=(go << 16)>>24;
addr[2]=(go << 8)>>24;
addr[3]=go>>24;
//用come()函數的地址覆蓋EIP
for(int j=0;j<4;j++)
{
buf[k-j-1]=addr[3-j];
}
}
void come()
{
printf("Success!");
}
一切搞定!運行之後,"Success!"成功列印出來!不過,由於這個程序破壞了堆棧,所以系統會提示程序遇到問題需要關閉。但這並不要緊,因為至少我們已經邁出了萬里長征的第一步。
F. 在c語言編程中,如何避免整數運算溢出問題
C語言編譯時不會檢查數據溢出問題,需要編程者自行注意數據溢出問題。而且據我的經驗數據溢出問題會頻繁出現在初學習當中,程序寫多了就很少出現這樣的問題了。