Ⅰ 什麼是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!"成功列印出來!不過,由於這個程序破壞了堆棧,所以系統會提示程序遇到問題需要關閉。但這並不要緊,因為至少我們已經邁出了萬里長征的第一步。
Ⅱ 用C語言編譯6度隔離理論
我不明白 六度隔離 理論,請在 補充回答 里說明。
比如一共30人,分別是1到30號。
而且,1號只認識2號,2號只認識3號……
那麼,1號認識30號就需要28個人了。
所以,六度隔離 理論是不是有什麼具體說明和限制,請說明,謝謝。
--------------------------------我來補充回答了--------------------------------
對不起,請不要復制網上的理論!
那個我在當初回答你的問題時就看過了,而且比你復制的全多了。
我有些不理解這個理論,具體不理解的地方也寫在上面了。
所以希望你可以給我解釋,然後我才能幫你編程,明白?
Ⅲ 沙漏C語言命令
用解析幾何的做法比較好,就是那兩條直線外的點為空白,直線內的區域為*即可,使用坐標法解。給你個框架,自己添加個頭文件和return,你應該知道怎麼做吧。
for(inti=0;i<9;i++)
for(intj=0;j<9;j++)
if(j>i&&(j-9<9-i))
printf("*");
else
printf("");
printf(" ");
Ⅳ C語言滑鼠如何顯示沙漏,求代碼
循環調用API函數SetCursor設置滑鼠游標,就可以了吧?我的C語言後半沒學好,之前用Vb做過。
Vb的VB聲明
Declare Function SetCursor Lib "user32" Alias "SetCursor" (ByVal hCursor As Long) As Long
說明
將指定的滑鼠指針設為當前指針
返回值
Long,前一個指針的值
參數表
參數 類型及說明
hCursor Long,要設為當前指針的一個指針的句柄。如設為零,表示不顯示任何指針
註解
在vb里這個函數不能很好的工作,因為vb習慣在不同的時間將指針變回原來的樣子
該API函數是調用User32.dll動態庫的
Ⅳ 關於C語言的:一個程序的漏洞修補
我覺得這題最好用switch分支,而且既然在「printf("請選擇運算符號(1為加,2為減,3為乘,4為除,5為關閉程序),程序會自動生成一個運算數不超過2位數的算術式:"); 」輸入字母時判斷為錯誤,我覺得後面就沒有再輸入答案的必要了,所以我改為在「printf("請選擇運算符號(1為加,2為減,3為乘,4為除,5為關閉程序),程序會自動生成一個運算數不超過2位數的算術式:"); 」前加一個" Loop:",把continue改為goto Loop;雖然在C中goto語句最好不使用,但我覺得這題足取!
Ⅵ c語言列印沙漏
寫一個函數a,用於列印一行, 弄幾個參數, 分別控制前面的空格的數量和*的熟練
寫個函數b, 在裡面調用a, 傳入不同的參數, 自己多練練, 沒人會往你手裡塞錢的, 需要自己探索
Ⅶ 為什麼C語言變數的地址每一次運行都是一樣的,在360隔離沙箱里運行也是一樣的
變數地址是由編譯器決定的
360隔離沙箱是不讓程序寫入磁碟,不是不讓程序載入內存
Ⅷ c語言:列印沙漏求大神講解意思
#include<stdio.h>
intmain()
{intsum,b,i,q,t,k,j,g,N;
charc;
sum=1;b=1;
scanf("%d%c",&N,&c);
for(i=1;sum<=N;i++)
{ b=b+2;//3+5+...
sum=sum+b*2;}//當sum大於N時結束循環,所需要的sum應為sum-2*b
i=i-1;
q=i;//保存沙漏的下半部分有多少行
sum=sum-2*b;//最大的沙漏所需要的字元數
k=0;
for(j=i;j>=1;j--)//後面沒什麼好說的,就是正常的分成上下兩部分,然後找行數和每行空格、字元數的關系
{for(g=1;g<=k;g++)
printf("");
for(t=1;t<=2*j-1;t++)
printf("%c",c);
printf(" ");
k++;
}
k=k-2;
for(j=2;j<=q;j++)
{for(g=1;g<=k;g++)
printf("");
for(t=1;t<=2*j-1;t++)
printf("%c",c);
printf(" ");
k--;}
printf("%d",N-sum);
return0;
}
Ⅸ c語言 輸出*形沙漏
#include <stdio.h >
void main ()
{
int i ,j, k, n;
scanf ("%d ",&n);
for (i =0 ;i<n;i++)
{
for (j =0 ;j <2*n;j++)
printf ("*");
printf ("\n");
}
for (i=1; i<=n-2;i++)
{for (j =1 ;j <=i;j++)
printf (" ");
for (k =1;k<=2*n-2*i;k++)
printf ("*");
printf ("\n");}
for (i =2;i<=n-2;i++)
{for(j =2;j>=i;j--)
{printf (" ");
}
for(k=1;k<=2*n-2*i;k++)
printf("*");
printf ("\n");}
for (i =0;i<n;i++)
{for (j=0;j<2*n;j++)
printf ("*");
printf ("\n");}
}
因電腦故障這個程序沒有調試,若有錯誤請您見諒
Ⅹ C語言如何將一段程序隔離出來正在編程,急急急!如題 謝謝了
首先,可以用中斷,第二簡單的比如,用一個標志位,i=xx;while(i--){一直在執行的語句 };{過段時間才執行的程序;},i=xx; 使用中斷就可以了 查看原帖>>