前言:網(wǎng)上關(guān)于緩沖區(qū)溢出的資料也有很多,但我在閱讀過程中發(fā)現(xiàn)介紹的都不是很明了,而且各網(wǎng)站也只是轉(zhuǎn)貼老外的那篇譯文而已,不僅內(nèi)容有缺損,而且程序也無法調(diào)通,因為GCC版本不一樣.經(jīng)過幾天的琢磨,終于明白了真正的原理,特地寫出來分享.
測試環(huán)境:
$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
Thread model: posix
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-24)
$ gdb -v
GNU gdb Red Hat Linux (6.0post-0.20031117.6rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu".
$ uname -a
Linux candy 2.4.21-9.EL #1 Thu Jan 8 17:03:13 EST 2004 i686 athlon i386 GNU/Linux
實例:
網(wǎng)上和我的這個實例雷同的也有,但是他們的是無法正確實現(xiàn)的.因為關(guān)鍵的跳轉(zhuǎn)代碼沒有計算正確.(GCC版本問題,呵呵)
/************
* a.c
************/
void function(void)
{
char buffer[5];
int* ret;
ret=buffer+28;
(*ret)+=10;
}
void main()
{
int x;
x=0;
function();
x=1;
printf("%d\n",x);
return;
}
/*end*/
懂C語言的人都會認為最后的輸出結(jié)果是1,可惜輸出結(jié)果為0.為什么呢?請聽解釋.
實例分析:
相關(guān)堆棧的基礎(chǔ)知識我就不羅嗦了,網(wǎng)上的介紹很多.
關(guān)鍵問題在于如何確定源代碼
ret=buffer+28;
(*ret)+=10;
中的28 和 10
編譯(會有warning,不用管他.)
$gcc -g -o a a.c //加上-g 用來在gdb中調(diào)試
$gdb a
(gdb)disas main //得到反匯編代碼 如下:
Dump of assembler code for function main:
0x08048366 : push %ebp
0x08048367 : mov %esp,%ebp
0x08048369 : sub $0x8,%esp
0x0804836c : and $0xfffffff0,%esp
0x0804836f : mov $0x0,%eax
0x08048374 : sub %eax,%esp
0x08048376 : movl $0x0,0xfffffffc(%ebp)
0x0804837d : call 0x8048348
0x08048382 : movl $0x1,0xfffffffc(%ebp)
0x08048389 : sub $0x8,%esp
0x0804838c : pushl 0xfffffffc(%ebp)
0x0804838f : push $0x8048474
0x08048394 : call 0x8048288
0x08048399 : add $0x10,%esp
0x0804839c : leave
0x0804839d : ret
End of assembler dump.
(gdb)disas function
Dump of assembler code for function function:
0x08048348 : push %ebp
0x08048349 : mov %esp,%ebp
0x0804834b : sub $0x28,%esp
0x0804834e : lea 0xffffffe8(%ebp),%eax
0x08048351 : add $0x1c,%eax
0x08048354 : mov %eax,0xffffffe4(%ebp)
0x08048357 : mov 0xffffffe4(%ebp),%edx
0x0804835a : mov 0xffffffe4(%ebp),%eax
0x0804835d : mov (%eax),%eax
0x0804835f : add $0xa,%eax
0x08048362 : mov %eax,(%edx)
0x08048364 : leave
0x08048365 : ret
End of assembler dump.
可以得知當main中執(zhí)行 0x0804837d : call 0x8048348 < function> 時 會將下一條指令的地址保存在堆棧中. 即 0x08048382 我們的目的就是要想這個值修改成下一條指令的地址 0x08048389 這樣就達到了屏蔽 x=1 這條語句了. 關(guān)鍵問題在于如何尋找保存0x08048382這個值的地址....
測試環(huán)境:
$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
Thread model: posix
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-24)
$ gdb -v
GNU gdb Red Hat Linux (6.0post-0.20031117.6rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu".
$ uname -a
Linux candy 2.4.21-9.EL #1 Thu Jan 8 17:03:13 EST 2004 i686 athlon i386 GNU/Linux
實例:
網(wǎng)上和我的這個實例雷同的也有,但是他們的是無法正確實現(xiàn)的.因為關(guān)鍵的跳轉(zhuǎn)代碼沒有計算正確.(GCC版本問題,呵呵)
/************
* a.c
************/
void function(void)
{
char buffer[5];
int* ret;
ret=buffer+28;
(*ret)+=10;
}
void main()
{
int x;
x=0;
function();
x=1;
printf("%d\n",x);
return;
}
/*end*/
懂C語言的人都會認為最后的輸出結(jié)果是1,可惜輸出結(jié)果為0.為什么呢?請聽解釋.
實例分析:
相關(guān)堆棧的基礎(chǔ)知識我就不羅嗦了,網(wǎng)上的介紹很多.
關(guān)鍵問題在于如何確定源代碼
ret=buffer+28;
(*ret)+=10;
中的28 和 10
編譯(會有warning,不用管他.)
$gcc -g -o a a.c //加上-g 用來在gdb中調(diào)試
$gdb a
(gdb)disas main //得到反匯編代碼 如下:
Dump of assembler code for function main:
0x08048366 : push %ebp
0x08048367 : mov %esp,%ebp
0x08048369 : sub $0x8,%esp
0x0804836c : and $0xfffffff0,%esp
0x0804836f : mov $0x0,%eax
0x08048374 : sub %eax,%esp
0x08048376 : movl $0x0,0xfffffffc(%ebp)
0x0804837d : call 0x8048348
0x08048382 : movl $0x1,0xfffffffc(%ebp)
0x08048389 : sub $0x8,%esp
0x0804838c : pushl 0xfffffffc(%ebp)
0x0804838f : push $0x8048474
0x08048394 : call 0x8048288
0x08048399 : add $0x10,%esp
0x0804839c : leave
0x0804839d : ret
End of assembler dump.
(gdb)disas function
Dump of assembler code for function function:
0x08048348 : push %ebp
0x08048349 : mov %esp,%ebp
0x0804834b : sub $0x28,%esp
0x0804834e : lea 0xffffffe8(%ebp),%eax
0x08048351 : add $0x1c,%eax
0x08048354 : mov %eax,0xffffffe4(%ebp)
0x08048357 : mov 0xffffffe4(%ebp),%edx
0x0804835a : mov 0xffffffe4(%ebp),%eax
0x0804835d : mov (%eax),%eax
0x0804835f : add $0xa,%eax
0x08048362 : mov %eax,(%edx)
0x08048364 : leave
0x08048365 : ret
End of assembler dump.
可以得知當main中執(zhí)行 0x0804837d : call 0x8048348 < function> 時 會將下一條指令的地址保存在堆棧中. 即 0x08048382 我們的目的就是要想這個值修改成下一條指令的地址 0x08048389 這樣就達到了屏蔽 x=1 這條語句了. 關(guān)鍵問題在于如何尋找保存0x08048382這個值的地址....