ICS15s-Ch3-prog-5_第1頁
ICS15s-Ch3-prog-5_第2頁
ICS15s-Ch3-prog-5_第3頁
ICS15s-Ch3-prog-5_第4頁
ICS15s-Ch3-prog-5_第5頁
已閱讀5頁,還剩31頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第三章 程序的轉換與機器級表示 越界訪問和緩沖區溢出 程序的轉換與機器級表示程序的轉換與機器級表示主要教學目標了解高級語言與匯編語言、匯編語言與機器語言之間的關系掌握有關指令格式、操作數類型、尋址方式、操作類型等內容了解高級語言源程序中的語句與機器級代碼之間的對應關系了解復雜數據類型(數組、結構等)的機器級實現主要教學內容介紹C語言程序與IA-32機器級指令之間的對應關系。主要包括:程序轉換概述、IA-32指令系統、C語言中控制語句和過程調用等機器級實現、復雜數據類型(數組、結構等)的機器級實現等。本章所用的機器級表示主要以匯編語言形式表示為主。采用逆向工程方法!程序的機器級表示程序的機器級表

2、示分以下五個部分介紹 第一講:程序轉換概述 機器指令和匯編指令 機器級程序員感覺到的屬性和功能特性 高級語言程序轉換為機器代碼的過程 第二講:IA-32 /x86-64指令系統 第三講: C語言程序的機器級表示 過程調用的機器級表示 選擇語句的機器級表示 循環結構的機器級表示 第四講:復雜數據類型的分配和訪問 數組的分配和訪問 結構體數據的分配和訪問 聯合體數據的分配和訪問 數據的對齊 第五講:越界訪問和緩沖區溢出 、x86-64架構從高級語言程序出發,用其對應的機器級代碼以及內存(棧)中信息的變化來說明底層實現圍繞C語言中的語句和復雜數據類型,解釋其在底層機器級的實現方法越界訪問和緩沖區溢出

3、 越界訪問和緩沖區溢出越界訪問和緩沖區溢出double fun(int i) volatile double d1 = 3.14; volatile long int a2; ai = 1073741824; /* Possibly out of bounds */ return d0;fun(0) 3.14fun(1) 3.14fun(2) 3.1399998664856fun(3) 2.00000061035156fun(4) 3.14, 然后存儲保護錯然后存儲保護錯 大家還記得以下的例子嗎?為什么當 i1 就有問題?因為數組訪問越界!越界訪問和緩沖區溢出越界訪問和緩沖區溢出 C語言中的數

4、組元素可使用指針來訪問,因而對數組的引用沒有邊界約束,也即程序中對數組的訪問可能會有意或無意地超越數組存儲區范圍而無法發現。數組存儲區可看成是一個緩沖區,超越數組存儲區范圍的寫入操作稱為緩沖區溢出。例如,對于一個有10個元素的char型數組,其定義的緩沖區有10個字節。若寫一個字符串到這個緩沖區,那么只要寫入的字符串多于9個字符(結束符0占一個字節),就會發生“寫溢出”。緩沖區溢出是一種非常普遍、非常危險的漏洞,在各種操作系統、應用軟件中廣泛存在。緩沖區溢出攻擊是利用緩沖區溢出漏洞所進行的攻擊行動。利用緩沖區溢出攻擊,可導致程序運行失敗、系統關機、重新啟動等后果。 越界訪問和緩沖區溢出越界訪問

5、和緩沖區溢出造成緩沖區溢出的原因是程序沒有對棧中作為緩沖區的數組進行越界檢查。#include stdio.h#include string.hvoid outputs(char *str) char buffer16; strcpy(buffer,str); printf(%s n, buffer);void hacker(void) printf(being hackedn);int main(int argc, char *argv) outputs(argv1); return 0;舉例:利用緩沖區溢出轉到自設的程序hacker去執行outputs漏洞:當命令行中字符串超25個字符時,

6、使用strcpy函數就會使緩沖buffer造成寫溢出并破壞返址 16+4+4+1=25越界訪問和緩沖區溢出越界訪問和緩沖區溢出反匯編得到的outputs匯編代碼 1 0 x080483e4 : push %ebp2 0 x080483e5 : mov %esp,%ebp3 0 x080483e7 : sub $0 x18,%esp4 0 x080483ea : mov 0 x8(%ebp),%eax5 0 x080483ed : mov %eax,0 x4(%esp)6 0 x080483f1 : lea 0 xfffffff0(%ebp),%eax7 0 x080483f4 : mov %e

7、ax,(%esp)8 0 x080483f7 : call 0 x8048330 9 0 x080483fc : lea 0 xfffffff0(%ebp),%eax10 0 x080483ff : mov %eax,0 x4(%esp)11 0 x08048403 : movl $0 x8048500,(%esp)12 0 x0804840a : call 0 x804831013 0 x0804840f : leave14 0 x08048410 : ret棧中分配了24B的空間將strcpy的兩個實參入棧將printf的兩個實參入棧若strcpy復制了25個字符到buffer中,并將ha

8、cker首址置于結束符0前4個字節,則在執行strcpy后,hacker代碼首址被置于main棧幀返回地址處,當執行outputs代碼的ret指令時,便會轉到hacker函數實施攻擊。越界訪問和緩沖區溢出越界訪問和緩沖區溢出#include stdio.hchar code= 0123456789ABCDEFXXXX x11x84x04x08 x00; int main(void) char *argv3; argv0=./test; argv1=code; argv2=NULL; execve(argv0,argv,NULL); return 0;通過execve()裝入test可執行文件,

9、并將code中的字符串作為命令行參數來啟動執行test。字符串中前16個字符”0123456789ABCDEF“ 被復制到buffer緩沖區,4個字符”XXXX“覆蓋掉EBP,地址0 x08048411覆蓋掉返回地址。執行上述攻擊程序后的輸出結果為:0123456789ABCDEFXXXX being hackedSegmentation fault 假定hacker函數對應代碼首址為0 x08048411,則如下代碼可實施攻擊最后顯示“Segmentation fault”,原因是在轉到hacker函數執行時是不正常的調用,并沒有保存其調用函數的返回地址,故在執行到hacker過程的ret指

10、令時取到的“返回地址”是一個不確定的值,因而可能跳轉到數據區或系統區或其他非法訪問的存儲區去執行,因而造成段錯誤。程序的加載和運行程序的加載和運行UNIX/Linux系統中,可通過調用execve()函數來啟動加載器。 execve()函數的功能是在當前進程上下文中加載并運行一個新程序。execve()函數的用法如下: int execve(char *filename, char *argv, *envp); filename是加載并運行的可執行文件名(如./hello),可帶參數列表argv和環境變量列表envp。若錯誤(如找不到指定文件filename),則返回-1,并將控制權交給調用程

11、序; 若函數執行成功,則不返回,最終將控制權傳遞到可執行目標中的主函數main。主函數main()的原型形式如下: int main(int argc, char *argv, char *envp); 或者: int main(int argc, char *argv, char *envp); argc指定參數個數,參數列表中第一個總是命令名(可執行文件名) 例如:命令行為“ld -o test main.o test.o” 時,argc=5 例中相當于“.test 0123456789ABCDEFXXXX ” ,argc=2程序的加載和運行程序的加載和運行Unixld -o test m

12、ain.o test.o若在shell命令行提示符下輸入以下命令行ld是可執行文件名(即命令名),隨后是命令的若干參數,argv是一個以null結尾的指針數組,argc=5在shell命令行提示符后鍵入命令并按“enter”鍵后,便構造argv和envp,然后調用execve()函數來啟動加載器,最終轉main()函數執行int execve(char int execve(char * *filename, char filename, char * *argv, argv, * *envp);envp);int main(int argc, char int main(int argc,

13、char * *argv, char argv, char * *envp);envp);假定有一個調用過程P調用了函數getline,其返回地址為0 x8048643,執行call指令調用getline時,部分寄存器的內容如下:Rebp=0 xbffffc94,Rebx=0 x1,Resi=0 x3,Redi=0 x2。執行程序時從標準輸入讀入的一行字符串為“012345678901234567890123”,此時,程序會發生段錯誤(segmentation fault)并中止執行,經調試確認錯誤是在執行getline的ret指令時發生的。回答下列問題或完成下列任務。1、畫出第7行和第10行

14、匯編指令后棧中的信息存放情況2、假如程序不發生段錯誤,則正確的返回地址是什么?,錯誤的返回地址是什么?3、執行完第10行匯編指令后,哪些寄存器的內容已被破壞?思考題思考題1、第第7行和第行和第10行匯編指令后行匯編指令后棧棧幀情況幀情況2、假如假如程序不發生段錯誤,則正確的返回地址程序不發生段錯誤,則正確的返回地址是是0 x8048643 ,錯誤錯誤的是的是0 x08048600 ?3、這些寄存器被破壞、這些寄存器被破壞緩沖區溢出攻擊的防范緩沖區溢出攻擊的防范兩個方面的防范 從程序員角度去防范 用輔助工具幫助程序員查漏,例如,用grep來搜索源代碼中容易產生漏洞的庫函數(如strcpy和spr

15、intf等)的調用;用fault injection查錯 從編譯器和操作系統方面去防范 地址空間隨機化ASLR 是一種比較有效的防御緩沖區溢出攻擊的技術目前在Linux、FreeBSD和Windows Vista等OS使用 棧破壞檢測 可執行代碼區域限制 等等圖6.30 Linux虛擬地址空間映像緩沖溢出攻擊防范緩沖溢出攻擊防范 地址空間隨機化 只要操作系統相同,則棧位置就一樣,若攻擊者知道漏洞程序使用的棧地址空間,就可設計一個針對性攻擊,在使用該程序機器上實施攻擊 地址空間隨機化(棧隨機化)的基本思路是,將加載程序時生成的代碼段、靜態數據段、堆區、動態庫和棧區各部分的首地址進行隨機化處理,使

16、每次啟動時,程序各段被加載到不同地址起始處 對于隨機生成的棧起始地址,攻擊者不太容易確定棧的起始位置緩沖區溢出攻擊的防范緩沖區溢出攻擊的防范 棧破壞檢測 若在程序跳轉到攻擊代碼前能檢測出程序棧已被破壞,就可避免受到嚴重攻擊 新GCC版本在代碼中加入了一種棧保護者(stack protector)機制,用于檢測緩沖區是否越界 主要思想:在函數準備階段,在其棧幀中緩沖區底部與保存寄存器之間(如buffer15與保留的EBP之間)加入一個隨機生成的特定值;在函數恢復階段,在恢復寄存器并返回到調用函數前,先檢查該值是否被改變。若改變則程序異常中止。因為插入在棧幀中的特定值是隨機生成的,所以攻擊者很難猜

17、測出它是什么緩沖區溢出攻擊的防范緩沖區溢出攻擊的防范 可執行代碼區域限制 通過將程序棧區和堆區設置為不可執行,從而使得攻擊者不可能執行被植入在輸入緩沖區的代碼,這種技術也被稱為非執行的緩沖區技術。 早期Unix系統只有代碼段的訪問屬性是可執行,其他區域的訪問屬性是可讀或可讀可寫。但是,近來Unix和Windows系統由于要實現更好的性能和功能,允許在棧段中動態地加入可執行代碼,這是緩沖區溢出的根源。 為保持程序兼容性,不可能使所有數據段都設置成不可執行。不過,可以將動態的棧段設置為不可執行,這樣,既保證程序的兼容性,又可以有效防止把代碼植入棧(自動變量緩沖區)的溢出攻擊。x86-64 IA-3

18、2浮點操作關鍵差別在于一條指令:fldl 和 fildl IA-32浮點操作舉例0IA-32和x86-64的比較例:以下是一段C語言代碼:#include main() double a = 10;printf(a = %dn, a);在IA-32上運行時,打印結果為a=0在x86-64上運行時,打印一個不確定值 為什么?在IA-32中a為float型又怎樣呢?先執行flds,再執行fstpl即:flds將32位單精度轉換為80位格式入浮點寄存器棧,fstpl再將80位轉換為64位送存儲器棧中,故實際上與a是double效果一樣!10=1010B=1.0123階碼e=1023+3=100000

19、00010B10的double型表示為:0 10000000010 01000B即4024 0000 0000 0000H先執行fldl,再執行fstplfldl:局部變量區ST(0)fstpl:ST(0) 參數區IA-32過程調用參數傳遞過程調用參數傳遞a的機器數對應十六進制為:40 24 00 00 00 00 00 00H參數1參數2打印結果總是全0X86-64過程調用參數傳遞過程調用參數傳遞 printf中為%d,故將從ESI中取打印參數進行處理;但a是double型數據,在x86-64中,a的值被送到XMM寄存器中而不會送到ESI中。故在printf執行時,從ESI中讀取的并不是a的

20、低32位,而是一個不確定的值。main() double a = 10;printf(a = %dn, a);.LC1: .string a = %dn“movsd .LC0(%rip), %xmm0 /a送xmm0movl $.LC1, %edi /RDI 高32位為0movl $1, %eax /向量寄存器個數call printfaddq $8, %rspret.LC0: .long 0 .long 1076101120 因為printf第2個參數為double型,故向量寄存器個數為100000000H40240000H小端方式!0存在低地址上X86-64架構架構 背景 Intel最早推

21、出的64位架構是基于超長指令字VLIW技術的IA-64體系結構,Intel 稱其為顯式并行指令計算機EPIC (Explicitly Parallel Instruction Computer)。安騰和安騰2分別在2000年和2002年問世,它們是IA-64體系結構的最早的具體實現。 AMD公司利用Intel在IA-64架構上的失敗,搶先在2003年推出兼容IA-32的64位版本指令集x86-64,AMD獲得了以前屬于Intel的一些高端市場。AMD后來將x86-64更名為AMD64。 Intel在2004年推出IA32-EM64T,它支持x86-64指令集。Intel為了表示EM64T的64

22、位模式特點,又使其與IA-64有所區別,2006年開始把EM64T改名為Intel 64。 X86-64架構架構與IA-32相比,x86-64架構的主要特點 新增8個64位通用寄存器:R8、R9、R10、R11、R12、R13、R14和R15。可作為8位(R8BR15B)、16位(R8WR15W)或32位寄存器(R8DR15D)使用 所有GPRs都從32位擴充到64位。8個32位通用寄存器EAX、EBX、ECX、EDX、EBP、ESP、ESI和 EDI對應擴展寄存器分別為RAX、RBX、RCX、RDX、RBP、RSP、RSI和RDI;EBP、ESP、ESI和 EDI的低8位寄存器分別是BPL、

23、SPL、SIL和DIL 字長從32位變為64位,故邏輯地址從32位變為64位 long double型數據雖還采用80位擴展精度格式,但所分配存儲空間從12B擴展為16B,即改為16B對齊,但不管是分配12B還是16B,都只用到低10B 過程調用時,通常用通用寄存器而不是棧來傳遞參數,因此,很多過程不用訪問棧,這使得大多數情況下執行時間比IA-32代碼更短 128位的MMX寄存器從原來的8個增加到16個,浮點操作采用基于SSE的面向XMM寄存器的指令集,而不采用基于浮點寄存器棧的指令集 X86-64架構架構 x86-64的基本指令和對齊 數據傳送指令(匯編指令中助記符“q”表示操作數長度為四字

24、(即64位) movabsq指令用于將一個64位立即數送到一個64位通用寄存器中; movq指令用于傳送一個64位的四字; movsbq、movswq、movslq用于將源操作數進行符號擴展并傳送到一個64位寄存器或存儲單元中; movzbq、movzwq用于將源操作數進行零擴展后傳送到一個64位寄存器或存儲單元中; pushq和popq分別是四字壓棧和四字出棧指令; movl指令的功能相當于movzlq指令 。X86-64架構架構 數據傳送指令舉例dest_type convert(source_type x) dest_type y = (dest_type) x;return y; 以下

25、函數功能是將類型為source_type的參數轉換為dest_type型數據并返回根據參數傳遞約定知,x在RDI對應的適合寬度的寄存器(RDI、EDI、DI和DIL)中,y存放在RAX對應的寄存器(RAX、EAX、AX或AL)中,填寫下表中的匯編指令以實現convert函數中的賦值語句問題:每種情況對應的匯編指令各是什么?X86-64架構架構 數據傳送指令舉例dest_type convert(source_type x) dest_type y = (dest_type) x;return y; 以下函數功能是將類型為source_type的參數轉換為dest_type型數據并返回根據參數傳

26、遞約定知,x在RDI對應的適合寬度的寄存器(RDI、EDI、DI和DIL)中,y存放在RAX對應的寄存器(RAX、EAX、AX或AL)中,填寫下表中的匯編指令以實現convert函數中的賦值語句只需x的低32位X86-64架構架構 算術邏輯運算指令 addq(四字相加) subq(四字相減) imulq(帶符號整數四字相乘) orq(64位相或) leaq(有效地址加載到64位寄存器)以下是C賦值語句“x=a*b+c*d;”對應的x86-64匯編代碼,已知x、a、b、c和d分別在寄存器RAX(x)、RDI(a)、RSI(b)、RDX(c)和RCX(d)對應寬度的寄存器中。根據以下匯編代碼,推測

27、x、a、b、c和d的數據類型 movslq %ecx, %rcximulq %rdx, %rcxmovsbl %sil, %esiimull %edi, %esimovslq %esi, %rsileaq (%rcx, %rsi), %raxd從32位符號擴展為64位,故d為int型在RDX中的c為64位long型在SIL中的b為char型在EDI中的a是int型在RAX中的x是long型X86-64架構架構 過程調用的參數傳遞 通過寄存器傳送參數 最多可有6個整型或指針型參數通過寄存器傳遞 超過6個入口參數時,后面的通過棧來傳遞 在棧中傳遞的參數若是基本類型,則都被分配8個字節 call(或callq)將64位返址保存在棧中之前,執行RrspRrsp-8 ret從棧中取出64位返回地址后,執行RrspRrsp+8 X86-64架構過程調用舉例架構過程調用舉例long caller ( ) char a=1; short b=2; int c=3; long d=4; test(a, &a, b, &b, c, &c, d, &d); return a*b+c*d;void test(char a, char *ap, short b, short *bp, int c, int *cp, long d,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論