導航:首頁 > 源碼編譯 > 未使用編譯器堆棧保護

未使用編譯器堆棧保護

發布時間:2023-05-03 09:33:07

A. 網路安全-----緩沖區溢出的保護方法有哪些

目前有四種基本的方法保護緩沖區免受緩沖區溢出的攻擊和影響。

編寫正確的代碼 非執行的緩沖區 數組邊界檢查 程序指針完整性檢查

一、編寫正確的代碼 Top

編寫正確的代碼是一件非常有意義但耗時的工作,特別像編寫C語言那種具有容易出錯傾向的程序(如:字元串的零結尾),這種風格是由於追求性能而忽視正確性的傳統引起的。盡管花了很長的時間使得人們知道了如何編寫安全的程序組具有安全漏洞的程序依舊出現。因此人們開發了一些工具和技術來幫助經驗不足的程序員編寫安全正確的程序。

最簡單的方法就是用grep來搜索源代碼中容易產生漏洞的庫的調用,比如對strcpy和sprintf的調用,這兩個函數都沒有檢查輸入參數的長度。事實上,各個版本C的標准庫均有這樣的問題存在。為了尋找一些常見的諸如緩沖區溢出和操作系統競爭條件等漏洞,一些代碼檢查小組檢查了很多的代碼。然而依然有漏網之魚存在。盡管採用了strcpy和sprintf這些替代函數來防止緩沖區溢出的發生,但是由於編寫代碼的問題,仍舊會有這種情況發生。比如lprm程序就是最好的例子,雖然它通過了代碼的安全檢查,但仍然有緩沖區溢出的問題存在。

為了對付這些問題,人們開發了一些高級的查錯工具,如faultinjection等。這些工具的目的在於通過人為隨機地產生一些緩沖區溢出來尋找代碼的安全漏洞。還有一些靜態分析工具用於偵測緩沖區溢出的存在。雖然這些工具可以幫助程序員開發更安全的程序,但是由於C語言的特點,這些工具不可能找出所有的緩沖區溢出漏洞。所以,偵錯技術只能用來減少緩沖區溢出的可能,並不能完全地消除它的存在,除非程序員能保證他的程序萬元一失。

二、非執行的緩沖區 Top

通過使被攻擊程序的數據段地址空間不可執行,從而使得攻擊者不可能執行被植入被攻擊程序輸入緩沖區的代碼,這種技術被稱為非執行的緩沖區技術。事實上,很多老的Unix系統都是這樣設計的,但是近來的Unix和MS Windows系統為實現更好的性能和功能,往往在數據段中動態地放人可執行的代碼。所以為了保持程序的兼容性不可能使得所有程序的數據段不可執行。但是我們可以設定堆棧數據段不可執行,這樣就可以最大限度地保證了程序的兼容性。Linux和Solaris都發布了有關這方面的內核補丁。因為幾乎沒有任何合的
程序會在堆棧中存放代碼,這種做法幾乎不產生任何兼容性問題,除了在Linux中的兩個特例,這時可執行的代碼必須被放入堆棧中:

1.信號傳遞

Linux通過向進程堆棧釋放代碼然後引發中斷來執行在堆棧中的代碼進而實現向進程發送Unix信號.非執行緩沖區的補丁在發送信號的時候是允許緩沖區可執行的.

2.GCC的在線重用

研究發現gcc在堆棧區里放置了可執行的代碼以便在線重用。然而,關閉這個功能並不產生任何問題.只有部分功能似乎不能使用。非執行堆棧的保護可以有效地對付把代碼植入自動變數的緩沖區溢出攻擊,而對於其他形式的攻擊則沒有效果。通過引用一個駐留
的程序的指針,就可以跳過這種保護措施。其他的攻擊可以採用把代碼植入堆或者靜態數據段中來跳過保護。

三、數組邊界檢查 Top

植入代碼引起緩沖區溢出是一個方面,擾亂程序的執行流程是另一個方面。不像非執行緩沖區保護,數組邊界檢查完全沒有了緩沖區溢出的產生和攻擊。這樣,只要數組不能被溢出,溢出攻擊也就無從談起。為了實現數組邊界檢查,則所有的對數組的讀寫操作都應當被檢查以確保對數組的操作在正確的范圍內。最直接的方法是檢查所有的數組操作,但是通常可以來用一些優化的技術來減少檢查的次數。目前有以下的幾種檢查方法:

1、Compaq C編譯

Compaq公司為Alpha CPU開發的C編譯器支持有限度的邊界檢查(使用—check_bounds參數)。這些限制是:只有顯示的數組引用才被檢查,比如「a[3]」會被檢查,而「*(a
+3)"則不會。由於所有的C數組在傳送的時候是指針傳遞的,所以傳遞給函數的的數組不會被檢查。帶有危險性的庫函數如strcpy不會在編譯的時候進行邊界檢查,即便是指定了邊界檢查。在C語言中利用指針進行數組操作和傳遞是非常頻繁的,因此這種局限性是非常嚴重的。通常這種邊界檢查用來程序的查錯,而且不能保證不發生緩沖區溢出的漏洞。

2、Jones&Kelly:C的數組邊界檢查

Richard Jones和Paul Kelly開發了一個gcc的補丁,用來實現對C程序完全的數組邊界檢查。由於沒有改變指針的含義,所以被編譯的程序和其他的gcc模塊具有很好的兼容性。更進一步的是,他們由此從沒有指針的表達式中導出了一個「基」指針,然後通過檢查這個基指針來偵測表達式的結果是否在容許的范圍之內。當然,這樣付出的性能上的代價是巨大的:對於一個頻繁使用指針的程序,如向量乘法,將由於指針的頻繁使用而使速度慢30倍。這個編譯器目前還很不成熟,一些復雜的程序(如elm)還不能在這個上面編譯、執行通過。然而在它的一個更新版本之下,它至少能編譯執行ssh軟體的加密軟體包,但其實現的性能要下降12倍。

3、Purify:存儲器存取檢查

Purify是C程序調試時查看存儲器使用的工具而不是專用的安全工具。Purify使用"目標代碼插入"技術來檢查所有的存儲器存取。通過用Purify連接工具連接,可執行代碼在執行的時候帶來的性能的損失要下降3—5倍。

4、類型——安全語言

所有的緩沖區溢出漏洞都源於C語言的類型安全。如果只有類型—安全的操作才可以被允許執行,這樣就不可能出現對變數的強制操作。如果作為新手,可以推薦使用具有類型—安全的語言如JAVA和ML。

但是作為Java執行平台的Java虛擬機是C程序.因此攻擊JVM的一條途徑是使JVM的緩沖區溢出。因此在系統中採用緩沖區溢出防衛技術來使用強制類型—安全的語言可以收到預想不到的效果。

四、程序指針完整性檢查 Top

程序指針完整性檢查和邊界檢查有略微的不同。與防止程序指針被改變不同,程序指針完整性檢查在程序指針被引用之前檢測到它的改變。因此,即便一個攻擊者成功地改變程序的指針,由於系統事先檢測到了指針的改變,因此這個指針將不會被使用。與數組邊界檢查相比,這種方法不能解決所有的緩沖區溢出問題;採用其他的緩沖區溢出方法就可以避免這種檢測。但是這種方法在性能上有很大的優勢,而且兼容性也很好。

l、手寫的堆棧監測

Snarskii為FreeBSD開發丁一套定製的能通過監測cpu堆棧來確定緩沖區溢出的libc。這個應用完全用手工匯編寫的,而且只保護libc中的當前有效紀錄函數.這個應用達到了設計要求,對於基於libc庫函數的攻擊具有很好的防衛,但是不能防衛其它方式的攻擊.

2、堆棧保護

堆棧保護是一種提供程序指針完整性檢查的編譯器技術.通過檢查函數活動紀錄中的返回地址來實現。堆棧保護作為gcc的一個小的補丁,在每個函數中,加入了函數建立和銷毀的代碼。加入的函數建立代碼實際上在堆棧中函數返回地址後面加了一些附加的位元組。而在函數返回時,首先檢查這個附加的位元組是否被改動過,如果發生過緩沖區溢出的攻擊,那麼這種攻擊很容易在函數返回前被檢測到。但是,如果攻擊者預見到這些附加位元組的存在,並且能在溢出過程中同樣地製造他們.那麼它就能成功地跳過堆棧保護的檢測。通常.我們有如下兩種方案對付這種欺騙:

1.終止符號

利用在C語言中的終止符號如o(null,CR,LF,—1(Eof)等這些符號不能在常用的字元串函數中使用,因為這些函數一旦遇到這些終止符號,就結束函數過程了。

2.隨機符號

利用一個在函數調用時產生的一個32位的隨機數來實現保密,使得攻擊者不可能猜測到附加位元組的內容.而且,每次調用附加位元組的內容都在改變,也無法預測。通過檢查堆棧的完整性的堆棧保護法是從Synthetix方法演變來的。Synthetix方法通過使用准不變數來確保特定變數的正確性。這些特定的變數的改變是程序實現能預知的,而且只能在滿足一定的條件才能可以改變。這種變數我們稱為准不變數。Synthetix開發了一些工具用來保護這些變數。攻擊者通過緩沖區溢出而產生的改變可以被系統當做非法的動作。在某些極端的情況下,這些准不變數有可能被非法改變,這時需要堆棧保護來提供更完善的保護了。實驗的數據表明,堆棧保護對於各種系統的緩沖區溢出攻擊都有很好的保護作用.並能保持較好的兼容性和系統性能。分析表明,堆棧保護能有效抵禦現在的和將來的基於堆棧的攻擊。堆棧保護版本的Red Hat Linux 5.1已經在各種系統上運行了多年,包括個人的筆記本電腦和工作組文件伺服器。

3、指針保護

在堆棧保護設計的時候,沖擊堆棧構成了緩沖區溢出攻擊的常見的一種形式。有人推測存在一種模板來構成這些攻擊(在1996年的時候)。從此,很多簡單的漏洞被發現,實施和補丁後,很多攻擊者開始用更一般的方法實施緩沖區溢出攻擊。指針保護是堆錢保護針對這種情況的一個推廣。通過在所有的代碼指針之後放置附加位元組來檢驗指針在被調用之前的合法性,如果檢驗失敗,會發出報警信號和退出程序的執行,就如同在堆棧保護中的行為一樣。這種方案有兩點需要注意:

(1)附加位元組的定位
附加位元組的空間是在被保護的變數被分配的時候分配的,同時在被保護位元組初始化過程中被初始化。這樣就帶來了問題:為了保持兼容性,我們不想改變被保護變數的大小,因此我們不能簡單地在變數的結構定義中加入附加字。還有,對各種類型也有不同附加位元組數目。

(2)查附加位元組
每次程序指針被引用的時候都要檢查附加位元組的完整性。這個也存在問題因為「從存取器讀」在編譯器中沒有語義,編譯器更關心指針的使用,而各種優化演算法傾向於從存儲器中讀人變數.還有隨著變數類型的不同,讀入的方法也各自不同。到目前為止,只有很少—部分使用非指針變數的攻擊能逃脫指針保護的檢測。但是,可以通過在編譯器上強制對某一變數加入附加位元組來實現檢測,這時需要程序員自己手工加入相應的保護了。

B. KEIL 中 PUSH

不能這樣寫,因為0x00不是特殊功能寄存器。要用嵌入式匯編的方法:

#pragma asm

PUSH 0x00

#pragma endasm

然慶扒後,選擇要嵌入式匯編的文件,然後右鍵

C. GCC編譯器局部變數地址分配為什麼總是從低

原因:GCC的堆棧保護技術—— canary的使用。
使用的原因是為了防止某些溢出的攻擊。但是只是溢出時方向發生了改變,並沒有起到太大的作用,可能對於傳統的一些攻擊方法有用。
GCC 中的堆棧保護實現
Stack Guard 是第一個使用 Canaries 探測的堆棧保護實現,它於 1997 年作為 GCC 的一個擴展發布。最初版本的 Stack Guard 使用 0x00000000 作為 canary word。盡管很多人建議把 Stack Guard 納入 GCC,作為 GCC 的一部分來提供堆棧保護。但實際上,GCC 3.x 沒有實現任何的堆棧保護。直到 GCC 4.1 堆棧保護才被加入,並且 GCC4.1 所採用的堆棧保護實現並非 Stack Guard,而是 Stack-smashing Protection(SSP,又稱 ProPolice)。
SSP 在 Stack Guard 的基礎上進行了改進和提高。它是由 IBM 的工程師 Hiroaki Rtoh 開發並維護的。與 Stack Guard 相比,SSP 保護函數返回地址的同時還保護了棧中的 EBP 等信息。此外,SSP 還有意將局部變數中的數組放在函數棧的高地址,而將其他變數放在低地址。這樣就使得通過溢出一個數組來修改其他變數(比如一個函數指針)變得更為困難。

D. 怎麼繞過內核堆棧檢測

1、使用緩沖區溢出技術,在程序運行期間答賀,繞過內核堆棧檢測,修改程序的返回地址,使其指向惡意代碼;

2、使用匯編技術,利用匯編指令來操作,繞過內核堆棧檢測,修改程清禪派襲野序的返回地址,使其指向惡意代碼;

3、使用軟體保護技術,如混淆和加殼技術,可以有效的繞過內核堆棧檢測,防止程序的返回地址被惡意修改;

4、使用編譯器優化技術,可以有效的繞過內核堆棧檢測,防止程序的返回地址被惡意修改。

E. 什麼叫「緩沖區益出保護」啊我的機器這幾天總出現這個問題

緩沖區溢出是當前一些軟體存在的最常見的安全隱患之一,通過提供一個惡意的輸入黑客可以改變進程的執行流程,緩沖區溢出能夠威脅到整個進程,機器,甚至相關的系統領域。如果運行的進程是在許可權比較高的用戶下面,比如administrator或者本地的系統帳戶(Local System Account),那麼黑客破壞所導致的損失將會很嚴重而且將會面臨更廣泛的潛在危脅。最近時期爆發的一些眾所周知的病毒像,紅色代碼病毒和震盪波蠕蟲病毒,都是C/C++代碼里存在著緩沖區溢出的結果。

1.什麼是緩沖區溢出?
~~~~~~~~~~~~~~~~~~~
buffer overflow,buffer overrun,smash the stack,trash the stack,
scribble the stack, mangle the stack,spam,alias bug,fandango on core,
memory leak,precedence lossage,overrun screw...
指的是一種系統攻擊的手段,通過往程序的緩沖區寫超出其長度的內容,造成緩沖區的溢出,從而破壞程序的堆棧,使程序轉而執行其它指令,以達到攻擊的目的。據統計,通過緩沖區溢出進行的攻擊占所有系統攻擊總數的80%以上。 造成緩沖區溢出的原因是程序中沒有仔細檢查用戶輸入的參數。

2.製造緩沖區溢出
~~~~~~~~~~~~~~~~
一個程序在內存中通常分為程序段,數據端和堆棧三部分。程序段里放著程序的機器碼和只讀數據。數據段放的是程序中的靜態數據。動態數據則通過堆棧來存放。在內存中,它們的位置是:

+------------------+ 內存低端
| 程序段 |
|------------------|
| 數據段 |
|------------------|
| 堆棧 |
+------------------+ 內存高端

當程序中發生函數調用時,計算機做如下操作:首先把參數壓入堆棧;然後保存指令寄存器(IP)中的內容做為返回地址(RET);第三個放入堆棧的是基址寄存器(FP);然後把當前的棧指針(SP)拷貝到FP,做為新的基地址;最後為本地變數留出一定空間,把SP減去適當的數值。

3.通過緩沖區溢出獲得用戶SHELL
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果在溢出的緩沖區中寫入我們想執行的代碼,再覆蓋返回地址(ret)的內 容,使它指向緩沖區的開頭,就可以達到運行其它指令的目的。

低內存端 buffer sfp ret *str 高內存端
<------ [ ][ ][ ][ ]
棧頂 ^ | 棧底
|________________________|

通常,我們想運行的是一個用戶shell。

4.利用緩沖區溢出進行的系統攻擊
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果已知某個程序有緩沖區溢出的缺陷,如何知道緩沖區的地址,在那兒放入shell代碼呢?由於每個程序的堆棧起始地址是固定的,所以理論上可以通過反復重試緩沖區相對於堆棧起始位置的距離來得到。但這樣的盲目猜測可能要進行數百上千次,實際上是不現實的。解決的辦法是利用空指令NOP。在shell代碼前面放一長串的NOP,返回地址可以指向這一串NOP中任一位置,執行完NOP指令後程序將激活shell進程。這樣就大大增加了猜中的可能性。

三. 緩沖區溢出的保護方法

目前有四種基本的方法保護緩沖區免受緩沖區溢出的攻擊和影響。在3.1中介紹了強制寫正確的代碼的方法。在3.2中介紹了通過操作系統使得緩沖區不可執行,從而阻止攻擊者殖入攻擊代碼。這種方法有效地阻止了很多緩沖區溢出的攻擊,但是攻擊者並不一定要殖入攻擊代碼來實現緩沖區溢出的攻擊(參見 2.1節),所以這種方法還是存在很弱點的。在3.3中,我們介紹了利用編譯器的邊界檢查來實現緩沖區的保護。這個方法使得緩沖區溢出不可能出現,從而完全消除了緩沖區溢出的威脅,但是相對而言代價比較大。在3.4中我們介紹一種間接的方法,這個方法在程序指針失效前進行完整性檢查。這樣雖然這種方法不能使得所有的緩沖區溢出失效,但它的的確確阻止了絕大多數的緩沖區溢出攻擊,而能夠逃脫這種方法保護的緩沖區溢出也很難實現。然後在3.5,我們要分析這種保護方法的兼容性和性能優勢(與數組邊界檢查)。

3.1 編寫正確的代碼

編寫正確的代碼是一件非常有意義但耗時的工作,特別象編寫C語言那種具有容易出錯傾向的程序(如:字元串的零結尾),這種風格是由於追求性能而忽視正確性的傳統引起的。盡管花了很長的時間使得人們知道了如何編寫安全的程序,具有安全漏洞的程序依舊出現。因此人們開發了一些工具和技術來幫助經驗不足的程序員編寫安全正確的程序。

最簡單的方法就是用grep來搜索源代碼中容易產生漏洞的庫的調用,比如對strcpy和sprintf的調用,這兩個函數都沒有檢查輸入參數的長度。事實上,各個版本C的標准庫均有這樣的問題存在。

為了尋找一些常見的諸如緩沖區溢出和操作系統競爭條件等漏洞,代碼檢查小組檢查了很多的代碼。然而依然有漏網之魚存在。盡管採用了 strncpy和snprintf這些替代函數來防止緩沖區溢出的發生,但是由於編寫代碼的問題,仍舊會有這種情況發生。比如lprm程序就是最好的例子,雖然它通過了代碼的安全檢查,但仍然有緩沖區溢出的問題存在。

為了對付這些問題,人們開發了一些高級的查錯工具,如fault injection等。這些工具的目的在於通過人為隨機地產生一些緩沖區溢出來尋找代碼的安全漏洞。還有一些靜態分析工具用於偵測緩沖區溢出的存在。

雖然這些工具幫助程序員開發更安全的程序,但是由於C語言的特點,這些工具不可能找出所有的緩沖區溢出漏洞。所以,偵錯技術只能用來減少緩沖區溢出的可能,並不能完全地消除它的存在。除非程序員能保證他的程序萬無一失,否則還是要用到以下3.2到3.4部分的內容來保證程序的可靠性能。

3.2 非執行的緩沖區

通過使被攻擊程序的數據段地址空間不可執行,從而使得攻擊者不可能執行被殖入被攻擊程序輸入緩沖區的代碼,這種技術被稱為非執行的緩沖區技術。事實上,很多老的Unix系統都是這樣設計的,但是近來的Unix和MS Windows系統由於實現更好的性能和功能,往往在在數據段中動態地放入可執行的代碼。所以為了保持程序的兼容性不可能使得所有程序的數據段不可執行。

但是我們可以設定堆棧數據段不可執行,這樣就可以最大限度地保證了程序的兼容性。Linux和Solaris都發布了有關這方面的內核補丁。因為幾乎沒有任何合法的程序會在堆棧中存放代碼,這種做法幾乎不產生任何兼容性問題,除了在Linux中的兩個特例,這時可執行的代碼必須被放入堆棧中:

信號傳遞:

Linux通過向進程堆棧釋放代碼然後引發中斷來執行在堆棧中的代碼來實現向進程發送Unix信號。非執行緩沖區的補丁在發送信號的時候是允許緩沖區可執行的。

GCC的在線重用:

研究發現gcc在堆棧區里放置了可執行的代碼作為在線重用之用。然而,關閉這個功能並不產生任何問題,只有部分功能似乎不能使用。

非執行堆棧的保護可以有效地對付把代碼殖入自動變數的緩沖區溢出攻擊,而對於其他形式的攻擊則沒有效果(參見2.1)。通過引用一個駐留的程序的指針,就可以跳過這種保護措施。其他的攻擊可以採用把代碼殖入堆或者靜態數據段中來跳過保護。

3.3 數組邊界檢查

殖入代碼引起緩沖區溢出是一個方面,擾亂程序的執行流程是另一個方面。不象非執行緩沖區保護,數組邊界檢查完全放置了緩沖區溢出的產生和攻擊。這樣,只要數組不能被溢出,溢出攻擊也就無從談起。為了實現數組邊界檢查,則所有的對數組的讀寫操作都應當被檢查以確保對數組的操作在正確的范圍內。最直接的方法是檢查所有的數組操作,但是通常可以採用一些優化的技術來減少檢查的次數。目前有以下的幾種檢查方法:

3.3.1 Compaq C 編譯器

Compaq公司為Alpha CPU開發的C編譯器(在Tru64的Unix平台上是cc,在Alpha Linux平台上是ccc)支持有限度的邊界檢查(使用-check_bounds參數)。這些限制是:

只有顯示的數組引用才被檢查,比如「a[3]」會被檢查,而「*(a+3)」則不會。

由於所有的C數組在傳送的時候是指針傳遞的,所以傳遞給函數的的數組不會被檢查。

帶有危險性的庫函數如strcpy不會在編譯的時候進行邊界檢查,即便是指定了邊界檢查。

由於在C語言中利用指針進行數組操作和傳遞是如此的頻繁,因此這種局限性是非常嚴重的。通常這種邊界檢查用來程序的查錯,而且不能保證不發生緩沖區溢出的漏洞。

3.3.2 Jones & Kelly: C的數組邊界檢查

Richard Jones和Paul Kelly開發了一個gcc的補丁,用來實現對C程序完全的數組邊界檢查。由於沒有改變指針的含義,所以被編譯的程序和其他的gcc模塊具有很好的兼容性。更進一步的是,他們由此從沒有指針的表達式中導出了一個「基」指針,然後通過檢查這個基指針來偵測表達式的結果是否在容許的范圍之內。

當然,這樣付出的性能上的代價是巨大的:對於一個頻繁使用指針的程序如向量乘法,將由於指針的頻繁使用而使速度比本來慢30倍。

這個編譯器目前還很不成熟;一些復雜的程序(如elm)還不能在這個上面編譯,執行通過。然而在它的一個更新版本之下,它至少能編譯執行ssh軟體的加密軟體包。其實現的性能要下降12倍。

3.3.3 Purify:存儲器存取檢查

Purify是C程序調試時查看存儲器使用的工具而不是專用的安全工具。Purify使用「目標代碼插入」技術來檢查所有的存儲器存取。通過用Purify連接工具連接,可執行代碼在執行的時候數組的所有引用來保證其合法性。這樣帶來的性能上的損失要下降3-5倍。

3.3.4 類型-安全語言

所有的緩沖區溢出漏洞都源於C語言缺乏類型安全。如果只有類型-安全的操作才可以被允許執行,這樣就不可能出現對變數的強制操作。如果作為新手,可以推薦使用具有類型-安全的語言如Java和ML。

但是作為Java執行平台的Java虛擬機是C程序,因此通過攻擊JVM的一條途徑是使JVM的緩沖區溢出。因此在系統中採用緩沖區溢出防衛技術來使用強制類型-安全的語言可以收到意想不到的效果。

3.4 程序指針完整性檢查

程序指針完整性檢查和邊界檢查由略微的不同。與防止程序指針被改變不同,程序指針完整性檢查在程序指針被引用之前檢測到它的改變。因此,即便一個攻擊者成功地改變了程序的指針,由於系統事先檢測到了指針的改變,因此這個指針將不會被使用。

與數組邊界檢查相比,這種方法不能解決所有的緩沖區溢出問題;採用其他的緩沖區溢出方法就可以避免這種檢測。但是這種方法在性能上有很大的優勢,而且在兼容性也很好。

程序完整性檢查大體上有三個研究方向。在3.4.1中會介紹Snarskii為FreeBSD開發了一套定製的能通過監測cpu堆棧來確定緩沖區溢出的libc。在3.4.2中會介紹我們自己的堆棧保護方法所開發的一個編譯器,它能夠在函數調用的時候自動生成完整性檢測代碼。最後在3.4.3,我們介紹正在開發中的指針保護方法,這種方法類似於堆棧保護,它提供對所有程序指針的完整性的保護。

3.4.1 手寫的堆棧監測

Snarskii為FreeBSD開發了一套定製的能通過監測cpu堆棧來確定緩沖區溢出的libc。這個應用完全用手工匯編寫的,而且只保護 libc中的當前有效紀錄函數。這個應用達到了設計要求,對於基於libc庫函數的攻擊具有很好的防衛,但是不能防衛其它方式的攻擊。

3.4.2 堆棧保護:編譯器生成的有效紀錄完整性檢測

堆棧保護是一種提供程序指針完整性檢查的編譯器技術,通過檢查函數活動紀錄中的返回地址來實現。堆棧保護作為gcc的一個小的補丁,在每個函數中,加入了函數建立和銷毀的代碼。加入的函數建立代碼實際上在堆棧中函數返回地址後面加了一些附加的位元組。而在函數返回時,首先檢查這個附加的位元組是否被改動過。如果發生過緩沖區溢出的攻擊,那麼這種攻擊很容易在函數返回前被檢測到。

但是,如果攻擊者預見到這些附加位元組的存在,並且能在溢出過程中同樣地製造他們,那麼他就能成功地跳過堆棧保護的檢測。通常,我們有如下的兩種方案對付這種欺騙:

終止符號:

利用在C語言中的終止符號如0(null),CR,LF,-1(EOF)等不能在常用的字元串函數中使用,因為這些函數一旦遇到這些終止符號,就結束函數過程了。

隨機符號:

利用一個在函數調用時產生的一個32位的隨機數來實現保密,使得攻擊者不可能猜測到附加位元組的內容。而且,每次調用,附加位元組的內容都在改變,也無法預測。

通過檢查堆棧的完整性的堆棧保護法是從Synthetix方法演變來的。Synthetix方法通過使用准不變數來確保特定變數的正確性。這些特定的變數的改變是程序實現能預知的,而且只能在滿足一定的條件才能可以改變。這種變數我們稱為准變數。Synthetix開發了一些工具用來保護這些變數。

攻擊者通過緩沖區溢出而產生的改變可以被系統當做非法的動作。在某些極端的情況下,這些准不變數有可能被非法改變,這是就需要堆棧保護來提供更完善的保護了。

實驗的數據表明,堆棧保護對於各種系統的緩沖區溢出攻擊都有很好的保護作用,並能保持較好的兼容性和系統性能。隨後,我們用堆棧保護的方法重新構造了一個完整的Linux系統(Red Hat 5.1)。然後我們用XFree86-3.3.2-5和lsof的漏洞對此進行了攻擊,結果表明,這個系統有效地抵禦了這些攻擊。這些分析表明,堆棧保護能有效抵禦現在的和將來的基於堆棧的攻擊。

堆棧保護版本的Red Hat Linux 5.1已經在各種系統上運行了多年,包括個人的筆記本電腦和工作組文件伺服器。從我們的Web伺服器上可以得到這個版本,而且在我們的郵件列表裡已經有了 55個成員。出了僅有的一次例外,這個系統和本來的系統工作完全一樣,這表明堆棧保護並不對系統的兼容性構成很大的影響。

我們已經用各種性能測試來評測堆棧保護的性能。Mircobenchmarks的結果表明在函數的調用,堆棧保護中增加了系統的

開銷。而在網路的測試中(需要用到堆棧保護的地方),則表明這種開銷不是很大。

我們的第一個測試對象是SSH,它提供了極強的加密和認證,用來替代Berkeley的r系列指令。SSH使用了軟體加密,因此系統的佔用的帶寬不大,我們用網路間復制一個大的文件來測試帶寬:

scp bigsource localhost:bigdest

測試結果表明:堆棧保護幾乎不影響SSH的網路吞吐性能。

第二個測試使用了Apache Web伺服器。如果這種伺服器存在基於堆棧的攻擊,那麼攻擊者就可以輕易地取得Web伺服器的控制權,允許攻擊者閱讀隱秘的內容和肆意篡改主頁的內容。同時,Web伺服器也是對性能和帶寬要求較高的一個伺服器部件。

我們用WebStone對帶有和不帶堆棧保護的Apache Web伺服器進行了測試。

和SSH一樣,他們的性能幾乎沒有區別。在客戶數目較少的情況下,帶有保護的伺服器性能比不帶保護的略微好些,在客戶端數目多的時候,不帶保護的性能好些。在最壞的情況下,帶保護的伺服器比不帶保護的要差8%的連接性能,而在平均延時上保持優勢。象以前一樣,我們把這些歸結為雜訊的影響。因此,我們的結論是:堆棧保護對Web伺服器系統性能沒有重大的影響。

3.4.3 指針保護:編譯器生成程序指針完整性檢查

在堆棧保護設計的時候,沖擊堆棧構成了緩沖區溢出攻擊的常見的一種形式。有人推測存在一種模板來構成這些攻擊(在1996年的時候)。從此,很多簡單的漏洞被發現,實施和補丁了,很多攻擊者開始用在第二部分中描述的更一般的方法實施緩沖區溢出攻擊。

指針保護是堆棧保護針對這種情況的一個推廣。通過在所有的代碼指針之後放置附加位元組來檢驗指針在被調用之前的合法性。如果檢驗失敗,會發出報警信號和退出程序的執行,就如同在堆棧保護中的行為一樣。這種方案有兩點需要注意:

附加位元組的定位:

附加位元組的空間是在被保護的變數被分配的時候分配的,同時在被保護位元組初始化過程中被初始化。這樣就帶來了問題;為了保持兼容性,我們不想改變被保護變數的大小,因此我們不能簡單地在變數的結構定義中加入附加字。還有,對各種類型也有不同附加位元組數目。

檢查附加位元組:

每次程序指針被引用的時候都要檢查附加位元組的完整性。這個也存在問題;因為「從存取器讀」在編譯器中沒有語義;編譯器更關心指針的使用,而各種的優化演算法傾向於從存儲器中讀入變數。

還有隨著不同類型的變數,讀入的方法也各自不同。

我們已經開發了指針保護的一個原型(還是基於gcc的),通過附加位元組來保護靜態分配的函數指針,但不適用於結構和數組類型。這個計劃還遠沒有完成。一旦這個項目完成了,那麼用它和堆棧保護構成的可執行代碼將不會受到緩沖區溢出的攻擊了。

目前為止,只有很少一部分使用非指針變數的攻擊能逃脫指針保護的檢測。但是,可以通過在編譯器上強制對某一變數加入附加位元組來實現檢測,這時需要程序員自己手工加入相應的保護了。

3.5 兼容性和性能的考慮

程序指針完整性檢查與邊界檢查相比,並不能防止所有的緩沖區溢出問題。然而在執行的性能和兼容性上具有相當的優勢:

性能:

邊界檢查必須在每個數組元素操作時完成一次檢查。相比之下,程序指針檢查只在被引用的時候實現檢查。無論在C還是在C++中,這種花在程序指針引用上的開銷始終比數組的指針引用小。

應用效能:

邊界檢查最難實現之處在於在C語言中,很能確定數組的邊界。這是由於在C中,數組的概念和通用指針的混用造成的。由於一個指針是一個獨立的對象,沒有與特定的邊界條件關聯,只有一個系統的機器字來存儲它,而標識邊界信息的數據卻沒有存放。因此需要特殊的方法來恢復這些信息;數組的引用將不在是一個簡單的指針,而是一個對緩沖區描述的指針組。

與現有代碼的兼容性:

一些邊界檢查方法為了與現有的代碼保持兼容而在系統的性能上得到了損失。而另一些則用別的方法達到目的。這樣就打破的傳統的C的轉換規則,轉而產生了一類新的C編譯器,只能編譯C的一個子集,有的還不能使用指針或者需要別的改變。

四 有效的組合

在這里我們研究、比較在第二部分描述的各種漏洞攻擊和在第三部分描述的防衛方法,以此來確定何種組合能完全消除緩沖區溢出問題。但是我們沒有把邊界檢查計算在內,因為它能有效地防止所有的緩沖區溢出,但是所需的開銷也是驚人的。

最普通的緩沖區溢出形式是攻擊活動紀錄然後在堆棧中殖入代碼。這種類型的攻擊在1996年中有很多紀錄。而非執行堆棧和堆棧保護的方法都可以有效防衛這種攻擊。非執行堆棧可以防衛所有把代碼殖入堆棧的攻擊方法,堆棧保護可以防衛所有改變活動紀錄的方法。這兩種方法相互兼容,可以同時防衛多種可能的攻擊。

剩下的攻擊基本上可以用指針保護的方法來防衛,但是在某些特殊的場合需要用手工來實現指針保護。全自動的指針保護需要對每個變數加入附加位元組,這樣使得指針邊界檢查在某些情況下具有優勢。

最為有趣的是,第一個緩沖區溢出漏洞--Morris蠕蟲使用了現今所有方法都無法有效防衛的方法,但是卻很少有人用到,也許是這種方法過於復雜的緣故吧。

五. 結論

在本文中,我們詳細描述和分析了緩沖區溢出的攻擊和防衛方法。由於這種攻擊是目前常見的攻擊手段,所以進行這個方面的研究工作是有意義和成效的。研究的結果表明,堆棧保護方法和非執行緩沖區方法對於當前絕大多數的攻擊都能有效地防禦,指針保護的方法可以對剩下的攻擊進行有效的防禦。最後聲明的是對於Morris蠕蟲的攻擊,迄今還沒有有效的防禦手段

F. 關於protues中仿所用的程序,用c語言編的程序和用匯編語言編寫的程序,哪個更有更有優勢

對於問題我想說以下幾點:
1.Proteus模擬時需要載入的是經過匯編(由匯編語言編寫的源程序文件時)或編譯與匯編(由C或其他高級語言編寫的源程序文件要先編譯成匯編語言告則,再匯編成hex、bin文件)的hex文件(稱為目標文件)。
2.Proteus與C語言沒有必然關系,要的只是hex文件,可以經過編譯生成hex文件的語言一大堆。
3.學好Proteus沒有成就遲者感,Proteus只適合一些小的設計,上不了正堂,而且Proteus模擬過的,實物不一定行的通,Proteus只適合理論上的初步驗證,當然學了還是多多益善。
4.匯編語言比C語言等在生成hex文件時形成指令的效率更高,比如,匯編語言幾乎每一句都有用,都會生成有效的二進制指令(除偽指令外),而C語言在生成二進制指令時有好多多餘的語句(比如函數調用時的不必要的入堆棧保護)。
5.匯編簡練,不易移植,不適合大一點的工程;C的編譯效率低,但是可移植性好,總之各有優勢,你現在看的應該是一些學習性的單片機程序,當然是小程序,經常襪旦棚遇到匯編就正常。
6.建議既要會C也要會匯編,這樣在以後用C等編寫的大工程中調試程序時,也可以知道某條語句其實現的原理,以便更好發現問題,解決問題。

G. dns溢出攻擊的條件

緩沖溢出漏洞危害不容忽視

當您在家裡通過寬頻體驗沖網的極速感覺時,當您在辦公室通過即時通訊軟體與遠在大洋彼岸的客戶商業交流時,是否想過您的系統是否堅如磐石,是否被網路另一端心懷叵測的黑客或腳本少年盯上。或許有人認為裝上了防火牆、防病毒就可以安全無憂了,遺憾的是這些僅解決了部分問題,而系統本身的漏洞而遭受攻擊卻極難防範。我們討論一種漏洞攻擊方式-----遠程緩沖溢出攻擊,因為這種攻擊可以使得一個匿名的Internet用戶有機會獲得一台主機的冊檔穗部分或全部的控制權,危害很大,也是最普遍的漏洞,大約80%的安全事件與緩沖區溢出有關。如最近微軟於7月17日公開的Windows安全漏洞「RPC介面緩存溢出可能導致運行任意代碼(MS03-026)」,其影響范圍和危害不亞於「SQL Slammer」,被認為至今微軟最嚴重緩沖溢出漏洞。

我們知道,緩沖區溢出漏洞是一種軟體中邊境條件、函數指針等設計不當的造成地址空間錯誤州卜,它的原理是:向一個有限空間的緩沖區中拷貝了過長的字元串,帶來了兩種後果,一是過長的字元串覆蓋了相臨的存儲單元而造成程序癱瘓,甚至造成宕機、系統或進程重啟等;二是利用漏洞可以讓攻擊者運行惡意代碼,執行任意指令,甚至獲得超級許可權等。

早在1988年,美國康奈爾大學的計算機科學系研究生,23歲的莫里斯(Morris)利用了UNIX fingered程序不限制輸入長度的漏洞使緩沖器溢出。Morris又寫了一段程序使他的惡意程序能以root(根)身份執行,並傳播到其他機器上,結果造成6000台Internet上的伺服器癱瘓,占當時總數的10%。 「SQL Slammer」蠕蟲王的發作原理,就是利用未及時更新補丁的MS SQL Server資料庫緩沖溢出漏洞。採用不正確的方式將數據發到MS Sql Server的監聽埠,這個錯誤可以引起緩沖溢出攻擊。目前新出現的MSBLAST病毒正是利用了微軟關於RPC 介面中遠程任意可執行代碼漏洞,「中招」的機器會反復重啟,或者拷貝、粘貼功能不工作等現象。事實上,如果成功利用緩沖漏洞,攻擊者就有可能獲得對遠程計算機的完全控制,並以本地系統許可權執行任意指令,如安裝程序、查看或更改、刪除數據、格式化硬碟等,危害性不言而喻。

通常緩沖區溢出攻擊都是一次完成攻擊代碼植入和程序轉向攻擊代碼兩種功能。如通常攻擊者將目標定為具有溢出漏洞的自動變數,然後向程序傳遞超長的字元串,進而引發緩沖區溢出。然後這段精巧設計的攻擊代碼以一定的許可權運行漏洞程序,既而獲得目標主機的控制權。這種攻擊手段屢次得逞主要利用了C程序中數組邊境條件、函數指針等設計不當的漏洞,大多數Windows、Linux、Unix、資料庫系列的開發都依賴於C語言,而C的缺點是缺乏類型安全,所以緩沖區溢出攻擊成為操作系統、資料庫等大型應用程序最普遍的漏洞公告之一。

面對漏洞威脅 積極應對防範

在1998年CERT的13份建議中,有9份是是與緩沖區溢出有關的,在1999年,蠢芹至少有半數的建議是和緩沖區溢出有關的。2003年7月份公開的10大安全漏洞通告至少有五項屬於緩沖區溢出漏洞。可見完全避免這種漏洞造成的安全威脅是不可能的,但我們可以構建完善的防範體系來降低沖區溢出攻擊的威脅。

作為編程人員可以使用具有類型-安全的語言 Java以避免C的缺陷;如果在C開發環境下應避免使用Gets、Sprintf等未限定邊境溢出的危險函數;此可使用檢查堆棧溢出的編譯器(如Compaq C編譯器)等。另外一個有效的辦法是採用非執行堆棧和堆棧保護的方法,最後在產品發布前仍需要仔細檢查程序溢出情況,將威脅降至最低。作為普通用戶或系統管理員應該做些什麼呢?首先確保及時為自己的操作系統和應用程序更新Patch,以修補公開的漏洞,其次應減少不必要的開放服務埠。舉一個例子,你屋子裡的門和窗戶越少,入侵者進入的方式就越少。

值得關注的是,通常傳統安全工具如防火牆對這種攻擊方式無能為力,因為攻擊者傳輸的數據分組並無異常特徵,沒有任何欺騙。另外可以用來實施緩存器溢出攻擊的字串非常多樣化,無法與正常數據有效進行區分。緩沖器溢出攻擊不是一種竊密和欺騙的手段,而是從計算機系統的最底層發起攻擊,因此在它的攻擊下系統的身份驗證和訪問許可權等安全策略形同虛設。

我們知道,單純依賴部署安全產品如防火牆、IDS等僅能構築靜態被動的防禦體系,所以還應注重P2DR模型的作用,即增加Policy(安全策略)、Protection(防護)、Detection(檢測)和Response(響應)的能力,按照公式Pt>Dt+Rt,和Et=Dt+Rt(Pt=0),應提高系統的防護時間Pt,降低檢測時間Dt和響應時間Rt。國內著名安全公司天行網安秉承安全視為一個過程,而非產品的技術理念,「全程網路安全服務」應運而生,其核心內容包括系統漏洞分析、安全風險評估、方案咨詢設計、狀態跟蹤與安全監控、事件緊急響應和安全修復等部分。「全程網路安全服務」不替代用戶現存的任何安全工具,而是充分發揮安全審計和管理平台的作用,構成主動的動態防禦體系,充分發揮安全工具的作用,降低威脅並保證網路的可持續健康運行。安全專家小組Security Force與安全專家、民間安全組織具有密切關系,他們具備精湛的技術和豐富的經驗,可以針對每一個用戶的特定需求和網路環境定製服務策略和服務內容,從而為用戶構建安全可信、可持續運行的網路應用平台。

H. 程序設計中,堆和棧比較重要。棧存取速度大於堆,而且編譯器可以修改棧大小,這個值可以隨意設置嗎

學習電腦編程多年了,在程序設計方面也算有一番見解,希望這些經驗能對題主有所幫助。

I. [gdb]函數堆棧亂掉的解決辦法 [轉]

程序core掉,要去debug,但是函數堆棧亂掉了,很惡心.....經過Google/wiki一番,找到兩種解決辦法.

x86ManualBacktrace


This tutorial will show you how to manually rebuild a backtrace with GDB on x86 using the stack frame pointer and current instruction pointer.
Consider the following gdb backtrace:

It's pretty clear that this is corrupted, evidence the following field:

Get the register information for the process:

On x86:

Stack Frame Layout for x86:

Color Key:blue

Using the current stack frame address from %ebp mp the stack above it:

Using this stack mp we know that the stack frame address in the %ebp register is the stack frame for the current instruction in the %eip register (unless this was a leaf function which didn't stack a frame but that's irrelevant for this discussion). Using the %ebp and %eip registers as a starting point we can build the first line in our backtrace rebuild:

When program control branches to a new function a stack frame is stacked and the callee function's last address is stored at the new frame's address %ebp + 4 (i.e. the last memory address in the callee's stack frame which is +4 from the current stack frame at %ebp). In order to get the caller's stack frame and instruction pointer just look at %ebp and %ebp+4:
In the stack find the memory at the stack frame in %ebp and the one at %ebp+4 (which will hold the callee's instruction pointer).

So using the address at 0xbf9ef358 and 0xbf9ef35c which is 0xbf9ef388 and 0x00d94cf7 continue to build our list:

Continue by looking at the next stack frame address 0xbf9ef388:

Keep doing this until we have a full back trace. You'll know you've reached the bottom of the stack when the previous stack frame pointer is 0x00000000.

Here's a complete manually rebuilt stack frame:

amd64下面,無非就是寄存器變成rbp,字長增加了一倍.當然這邊選擇了手動尋找函數返回地址,然後info symbol列印出函數名,其實還可以通過gdb格式化來直接列印函數名:
gdb>x/128agrbp內的內容
所以手動還原的辦法就變得很簡單:
gdb>info reg rbp*x86換成info reg ebp
gdb>x/128ag rbp內的內容 *x86換成 x/128aw ebp的內容
這樣就能看到函數棧.如果你想解析參數是啥,也是可以的,只是比較麻煩,苦力活兒....想解析參數,就要知道棧的布局,可以參考這篇文章: http://blog.csdn.net/liigo/archive/2006/12/23/1456938.aspx

昨天和 海洋 一塊研究了下函數調用棧,順便寫兩句。不足或錯誤之處請包涵!
理解調用棧最重要的兩點是:棧的結構,EBP寄存器的作用。
首先要認識到這樣兩個事實:
1、一個函數調用動作可分解為:零到多個PUSH指令(用於參數入棧),一個CALL指令。CALL指令內部其實還暗含了一個將返回地址(即CALL指令下一條指令的地址)壓棧的動作。
2、幾乎所有本地編譯器都會在每個函數體之前插入類似如下指令:PUSH EBP; MOV EBP ESP;
即,在程序執行到一個函數的真正函數體時,已經有以下數據順序入棧:參數,返回地址,EBP。由此得到類似如下的棧結構(參數入棧順序跟調用方式有關,這里以 C語言 默認的CDECL為例):

「PUSH EBP」「MOV EBP ESP」這兩條指令實在大有深意:首先將EBP入棧,然後將棧頂指針ESP賦值給EBP。「MOV EBP ESP」這條指令表面上看是用ESP把EBP原來的值覆蓋了,其實不然——因為給EBP賦值之前,原EBP值已經被壓棧(位於棧頂),而新的EBP又恰恰指向棧頂。
此時EBP寄存器就已經處於一個非常重要的地位,該寄存器中存儲著棧中的一個地址(原EBP入棧後的棧頂),從該地址為基準,向上(棧底方向)能獲取返回地址、參數值,向下(棧頂方向)能獲取函數局部變數值,而該地址處又存儲著上一層函數調用時的EBP值!
一般而言,ss:[ebp+4]處為返回地址,ss:[ebp+8]處為第一個參數值(最後一個入棧的參數值,此處假設其佔用4位元組內存),ss:[ebp-4]處為第一個局部變數,ss:[ebp]處為上一層EBP值。
由於EBP中的地址處總是「上一層函數調用時的EBP值」,而在每一層函數調用中,都能通過當時的EBP值「向上(棧底方向)能獲取返回地址、參數值,向下(棧頂方向)能獲取函數局部變數值」。如此形成遞歸,直至到達棧底。這就是函數調用棧。
編譯器對EBP的使用實在太精妙了。
從當前EBP出發,逐層向上找到所有的EBP是非常容易的:

這個辦法比較簡單,很容易實踐,但是有一個前提,如果棧的內容被沖刷干凈了,你連毛都看不到(事實就是這樣).所以你需要開始棧保護...至少你還能找到棧頂的函數...
gcc有參數: -fstack-protector 和 -fstack-protector-all,強烈建議開啟....

**********************************************************************/

用列印方法調試
在客戶項目那裡混了半年,發現Top的客戶確實是比我們牛逼。先說說調試的方法。
客戶那邊不依賴於GDB調試,因為他們可能覺得GDB依賴於系統 實現,不利於移植吧,所以客戶的程序完全是依賴於列印調試的。這點很佩服他們的軟體規劃能力和項目管理,實現能力。說老實話,如果換了一家中國公司,每人 一個調試方法,要follow 一個rule是很不容易的。
完善的調試菜單。調試菜單並不難實現,只是一個列印和字元接受的函數。在其中控制是開放某些列印信息。
在每個模塊中加上仔細規劃列印輸出,根據需求分成不同的基本。最好情況是在最高列印級別中可以可以發現所有的問題。列印級別可以很方便的動態控制。
函數調用LOG
如果能定位發生問題的模塊,可以在該模塊的在每個函數的調用入口加上列印一個函數名字+Enter,在返回處加上一個函數名字+Exit。對於每個模塊用一個列印開關控制是否列印Trace信息。在調試菜單中控制這個列印開關。
如果懶得加列印語句,可以利用gcc 的-finstrument-functions 選項來快速的加入調試信息。-finstrumnet-function會是的編譯器在函數調用的開始和退出處調用

可以利用這兩個函數來跟蹤函數調用的過程。
在 實現這兩個函數時要加入 attribute ((no_instrument_function));以避免編譯器再調用這兩個函數的時候也調用__cyg_profile_func_enter 和 __cyg_profile_func_exit 而造成循環調用。
可以用dladdr()來獲得this_fn的文件和函數名。code如下:

// 由於dladdr是GNU擴展,不是dl的標准函數,因此在這句話必須加在文件的開始處

關於列印堆棧。可以用

該方法需要編譯器支持。
但是需要在編譯的時候加上-rdynamic 否則只能輸出在內存中的絕對地址。
在沒有-rdynamic的時候,關於如何找到動態庫的運行時地址還需要研究。
可以在系統運行的時候發送SIGSEGV給應用程序,產生當前進程的Coremp來獲取動態庫中函數的運行是地址。
用GDB獲取backtrace的方法(在有-g選項的時候可以看到,不需要-rdynamic):
list <*address>

在沒有-g的時候,又該如何呢?

閱讀全文

與未使用編譯器堆棧保護相關的資料

熱點內容
java是不是數字 瀏覽:180
php模擬瀏覽器環境 瀏覽:351
編程誰都能學會嗎 瀏覽:407
使用國家反詐app都要開啟什麼 瀏覽:712
下載民宿APP有什麼用 瀏覽:50
續子語pdf 瀏覽:385
2021年加密貨幣最新行情 瀏覽:162
nfs怎麼加密ipsec 瀏覽:245
國二考試調用編譯器運算選擇題 瀏覽:750
同濟大學高等數學pdf 瀏覽:234
延時的宏命令怎麼設置 瀏覽:596
資料庫有哪些加密 瀏覽:209
改之理反編譯注冊教程 瀏覽:391
什麼是編譯程序和翻譯程序 瀏覽:208
python課程心得總結 瀏覽:17
派派中怎麼看對方在哪個伺服器 瀏覽:796
xp配置java環境變數配置 瀏覽:9
python中1到100怎麼算 瀏覽:768
小度我想看程序員 瀏覽:508
bs刷裝備建立後文件夾沒有 瀏覽:81