菜鸟问堆栈溢出问题

wwwhhb4001 2009-02-08 10:47:36

刚刚在网上看了段代码

#include <stdio.h>;
void overFlow ()
{
int a[] = { 0x78787868 };
*(a + 2) += 7;
}

int main ()
{
int aa = 3;
overFlow ();
aa = 4;
printf ("%d\n", aa);
}


结果是3,overflow()跳过了AA=4

我不明白 overflow() 为什么会跳过 aa=4

overflow()是个函数, a[]是她的局部变量,不是调用函数时候,都要保护现场,函数返回都要恢复现场吗?

难到这里不恢复现场?

高手指点一下,如果用汇编来说明更好,谢谢

...全文
186 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
梅文海 2009-02-09
  • 打赏
  • 举报
回复
呵呵!这段代码写的比较巧妙,一般我们都直接用 __declspec( naked ) 来写的
他巧妙的利用了栈的特性,用c代码实现了一个任意 ret
机智的呆呆 2009-02-08
  • 打赏
  • 举报
回复
http://blog.csdn.net/Demon__Hunter/archive/2008/11/30/3414219.aspx
机智的呆呆 2009-02-08
  • 打赏
  • 举报
回复
*(a + 3) += 7 vs2005 debug中才是eip值
机智的呆呆 2009-02-08
  • 打赏
  • 举报
回复
*(a + 2) += 7;//关键是这句 a是分配在栈上的,由于函数调用时esp ebp eip等寄存器也入栈保存 所以通过栈上的变量的缓冲区溢出就可以修改这些保存在栈中寄存器得值尤其是eip的值。如果编译器不加缓冲区保护的话,如vs 的GS编译选项 那么a+1就是保存在栈中的ebp得值,a+2 就是eip的值,由于aa=4 语句对应二进制代码是7个字节,默认void overFlow () 返回要执行aa=4语句,但*(a + 2) += 7修改了eipd得值跳过了这一句 执行了aa = 4后的printf ("%d\n", aa);
arong1234 2009-02-08
  • 打赏
  • 举报
回复
这有什么灵异得?他不是内存访问越界了么

[Quote=引用 6 楼 zhh157 的回复:]
可否列为灵异事件?
望达人解析
[/Quote]
deerwin1986 2009-02-08
  • 打赏
  • 举报
回复
首先 这个在DEBUG模式下是看不到效果的(系统会加 INT 3中断检测栈溢出) 要看效果 先设置为RELEASE模式 然后把优化级别设置为 禁用优化(否则编译器有可能会把其中的语句甚至函数调用优化掉)
才能看到"3"的结果
原理也很简单 在函数中直接修改了函数本身栈桢中的函数返回地址 直接忽略掉了aa = 4;
直接返回到printf();
具体看反汇编就明白了...
tangshuiling 2009-02-08
  • 打赏
  • 举报
回复
[Quote=引用楼主 wwwhhb4001 的帖子:]

刚刚在网上看了段代码

#include <stdio.h>
void overFlow ()
{
int a[] = { 0x78787868 };
*(a + 2) += 7;
}

int main ()
{
int aa = 3;
overFlow ();
aa = 4;
printf ("%d\n", aa);
}
先谈谈为何vs2005编译不过的问题,vs2005有检查数组大小(也可能叫检查堆栈大小)的选项,关掉后可以正常运行
函数overFlow被调用时,必须首先维护自己的一个栈结构(注意:栈是从高地址->低地址的生长方向,至少win32系统是如此),大概是这个样子:(指令寄存器EIP为aa=4地址,EBP,栈变量a首地址),这就是荣哥说的保护现场!
为何要保护现场,我想楼主应该清楚吧,毕竟函数return后还要回到aa=4这条指令的执行
由于*(a+2)+=7刻意对栈保存的EIP值加以修改,因此,函数overFlow返回后就跳过了aa=4这条指令

[/Quote]
old-six-programmer 2009-02-08
  • 打赏
  • 举报
回复
可否列为灵异事件?
望达人解析
old-six-programmer 2009-02-08
  • 打赏
  • 举报
回复
可否列为灵异事件?
望达人解析
  • 打赏
  • 举报
回复
汇编机制就不了解了,但是你这里int a[]不仅溢出,还越界操作。
wanlxp 2009-02-08
  • 打赏
  • 举报
回复
vs 2005里面能执行错误,你这个代码有错误。。
chenzhp 2009-02-08
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 arong1234 的回复:]
所谓的“现场”是指寄存器,而不是堆栈,自动变量都是放在堆栈上的,是不会保护的(如果每个内存每个变量都保护,你得多少内存去保护?
[/Quote]
是的
arong1234 2009-02-08
  • 打赏
  • 举报
回复
所谓的“现场”是指寄存器,而不是堆栈,自动变量都是放在堆栈上的,是不会保护的(如果每个内存每个变量都保护,你得多少内存去保护?
xmu_才盛 2009-02-08
  • 打赏
  • 举报
回复
堆中函数的开销讲起:

缓冲区:

本函数局部变量,栈底指针,返回地址,函数参数,对齐,外部调用函数的局部变量

局部变量 ------a= 0x87878786 (int 型)
栈底指针 ------a+1= 0x…… (int 型)
返回地址 ------a+2= 0x…… (int 型 这个事汇编代码在内存中的地址)



下面我们看一下反汇编代码
[color=#FF0000]……
14: aa = 4;
004010D2 mov dword ptr [ebp-4],4
15: printf ("%d\n", aa);
004010D9 mov ecx,dword ptr [ebp-4]
……
很明显 a+2存储的是 0x004010D2,也就是aa=4的执行地址
显而易见 0x004010D9 是printf的地址

0x004010D9-0x004010D2==7!!!

所以*(a+2)+7跳过了 aa=4的执行代码
Proteas 2009-02-08
  • 打赏
  • 举报
回复
发汇编你的程序,然后看看参数是怎么入栈出栈的.

65,211

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧