亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

緩沖區(qū)溢出解密二

互聯(lián)網(wǎng)   發(fā)布時間:2008-10-08 19:04:07   作者:佚名   我要評論
而如果ESP被PUSH到堆棧,這是堆棧的表示: |_parametre_I___| EBP 12 |_parametre II__| EBP 8 |_return adress_| EBP 4 |___saved_ESP___| EBP ESP |_local var I __| EBP-4 |_local var II__| EBP-8 在上面的圖中,變量I 和II是

而如果ESP被PUSH到堆棧,這是堆棧的表示:
|_parametre_I___| EBP 12
|_parametre II__| EBP 8
|_return adress_| EBP 4
|___saved_ESP___| EBP ESP
|_local var I __| EBP-4
|_local var II__| EBP-8
在上面的圖中,變量I 和II是傳遞給函數(shù)的參數(shù)。在返回地址和保存ESP之后,var I和II是函數(shù)的局部變量。現(xiàn)在,如果我們總結所有我們所講的,當調(diào)用一個函數(shù)的時候:
1.我們保存老的堆棧指針,PUSH它到堆棧 2.我們保存下一個指令的地址(返回地址),PUSH它到堆棧。3.我們開始執(zhí)行程序指令。
當我們調(diào)用一個函數(shù)時,上面3步都做了。
讓我們在一個生動的例子中看堆棧的操作。
a.c :
void f(int a, int b, int c)
{
char z[4];
}
void main()
{
f(1, 2, 3);
} 用-g標志編譯這個從而能夠調(diào)試:
[murat@victim murat]$ gcc -g a.c -o a
讓我們看看這里發(fā)生了什么:
[murat@victim murat]$ gdb -q ./a
(gdb) disas main
Dump of assembler code for function main:
0x8048448 : pushl 雙
0x8048449 : movl %esp,雙
0x804844b : pushl $0x3
0x804844d : pushl $0x2
0x804844f : pushl $0x1
0x8048451 : call 0x8048440
0x8048456 : addl $0xc,%esp
0x8048459 : leave
0x804845a : ret
End of assembler dump.
(gdb)
以上可見,main()函數(shù)中第一個指令是:
0x8048448 : pushl 雙
它支持老的指針,并把它壓入堆棧。接著,拷貝老的堆棧指針倒ebp寄存器:
0x8048449 : movl %esp,雙
因而,從那時起,在函數(shù)中,我們將用EBP引用函數(shù)的局部變量。這兩個指令被稱為”程序引入”。接著,我們反序PUSH函數(shù)f()的參數(shù)到堆棧中。
0x804844b : pushl $0x3
0x804844d : pushl $0x2
0x804844f : pushl $0x1
我們調(diào)用這個函數(shù):
0x8048451 : call 0x8048440
如我們已經(jīng)通過CALL調(diào)用解釋的那樣,我們PUSH指令addl $0xc,%esp的地址0x8048456到堆棧。函數(shù)RET調(diào)用后,我們加12或者十六進制中的0xc(因為我們推入3個參數(shù)到堆棧中,每一個分配了4個字節(jié)(整型))。 接著我們離開main()函數(shù),并且返回:
0x8048459 : leave
0x804845a : ret
好,在函數(shù)f()內(nèi)部發(fā)生了什么呢?
(gdb)
disas f
Dump of assembler code for function f:
0x8048440 : pushl 雙
0x8048441 : movl %esp,雙
0x8048443 : subl $0x4,%esp
0x8048446 : leave
0x8048447 : ret
End of assembler dump.
(gdb)
開始兩個指令都是一樣的。它們是程序引入。接著我們看a:
0x8048443 : subl $0x4,%esp
從ESP減去了4個字節(jié)。這是為局部變量z分配空間。記得我們定義它為char z[4]?它是一個4字節(jié)的字符數(shù)組。最后,在末尾,函數(shù)返回:
0x8048446 : leave
0x8048447 : ret

好,讓我們看另外一個例子:
b.c :
void f(int a, int b, int c)
{
char foo1[6];
char foo2[9];
}
void main()
{
f(1,2,3);
}
編譯并且啟動gdb,解析f:
[murat@victim murat]$ gcc -g b.c -o b
[murat@victim murat]$ gdb -q ./b
(gdb) disas f
Dump of assembler code for function f:
0x8048440 : pushl 雙
0x8048441 : movl %esp,雙
0x8048443 : subl $0x14,%esp
0x8048446 : leave
0x8048447 : ret
End of assembler dump.
(gdb)
可以看出,從ESP中減去了0x14(20字節(jié)),盡管foo1和foo2的總長度只有9 6=15。這樣的原因是,內(nèi)存,還有堆棧,在4字節(jié)框架下編址。這意味著,你不能簡單的PUSH 1字節(jié)數(shù)據(jù)到堆棧中?;蛘?字節(jié)或者為空。 f()北調(diào)用時,堆棧將象這樣:
|_______$1_______| EBP 16
|_______$2_______| EBP 12
|_______$3_______| EBP 8
|_return address_| EBP 4
|___saved_ESP____| EBP ESP
|______foo1______| EBP-4
|______foo1______| EBP-8
|______foo2______| EBP-12
|______foo2______| EBP-16
|______foo2______| EBP-20
你可以相信,當我們對f001裝載超過8個字節(jié)對和對foo2超過12個字節(jié),我們將溢出他們的空間。如果你對foo1寫入超過4個字節(jié),你將重寫被保護的EBP,而且……如果你寫入超過4個字節(jié),你將重寫返回地址……而這不正是我們都想要的嗎?這是內(nèi)存溢出的基礎……讓我設法用一段簡單的代碼稍微闡明一下這種現(xiàn)象,假設我們有這樣的代碼:
c.c :
#include
void f(char *str)
{
char foo[16];
strcpy(foo, str);
}
void main()
{
char large_one[256];
memset(large_one, 'A', 255);
f(large_one);
}
[murat@victim murat]$ make c
cc -W -Wall -pedantic -g c.c -o c
[murat@victim murat]$ ./c
Segmentation fault (core dumped)
[murat@victim murat]$
我們在上面做的是簡單的寫255字節(jié)到一個只能容納16字節(jié)的數(shù)組里。我們傳遞了一個256字節(jié)的大數(shù)組作為一個參數(shù)給f()函數(shù)。在函數(shù)內(nèi)部,沒有邊界檢測我們拷貝了整個large_one到foo,溢出了foo和其它數(shù)據(jù)。因此緩沖區(qū)被填寫了,同樣的strcpy()用A填寫了內(nèi)存的其它部分,包括返回地址。
這里是用gdb生成核文件代碼的檢查:
[murat@victim murat]$ gdb -q c core
Core was generated by `./c'.
Program terminated with signal 11, Segmentation fault.
find_solib: Can't read pathname for load map: Input/output error
#0 0x41414141 in ?? ()
(gdb)
可以看出,CPU在EIP中看到0x41414141(041是字母A的十六進制ASCII碼),試圖存儲和執(zhí)行此處的指令。然而,0x41414141不是我們的程序被允許存儲的內(nèi)存地址。最后操作系統(tǒng)發(fā)了一個SIGSEGV(Segmentation Violation)段侵犯信號給程序并且停止了任何進一步的操作。
我們調(diào)用f()時,堆??雌饋硐筮@樣:
|______*str______| EBP 8
|_return address_| EBP 4
|___saved_ESP____| EBP ESP
|______foo1______| EBP-4
|______foo1______| EBP-8
|______foo1______| EBP-12
|______foo1______| EBP-16
strcpy()從foo1的開頭,EBP-16開始,拷貝large_one到foo,沒有邊界檢查,用A填充了整個堆棧。
現(xiàn)在我們能夠重寫返回地址,如果我們放一些其它的內(nèi)存段地址,我們能在那里執(zhí)行指令碼?答案是肯定的。假如我們放了一些 /bin/sh spawn出的指令在一些內(nèi)存地址中,而我們把這個地址放到我們溢出的這個函數(shù)返回地址中,我們就能spawn出一個shell,而且很有可能,既然你已經(jīng)對setuid二進制程序感興趣了,我們將spawn出一個root shell。

相關文章

最新評論