一段简单程序引发的栈故事

先看下面一段程序:

初步看,Test这个函数很不和谐,p是个局部变量,而返回值也是它,函数返回时它的空间就不复存在了。可当你写代码写得晕头转向的时候,转念一想,p也是个常量指针,"hello world!"这个串并不存储在栈区,而存储于常量区呀,即使栈的内容消失了,返回指向常量区的一个指针也不会有什么问题。

那就试试吧。

在15行 printf(str)处设置断点,DEBUG,运行到断点处的时候,发现str指向确实是"hello world!"串,而且n的值也是12,心中窃喜!继续单步执行,打印出来的结果却不是原来str中的串,变成了"hell??"只有前面4个字节还在,后面的内容全没了,而且str中的内容也是这个"hell??"了,难道在printf中有什么秘密?

于是再手工打造一个简单字符串拷贝函数,程序改写成下:

继续调试,发现执行完copystr后,str中的内容变成了“烫烫烫”,看来不是printf引起的问题,肯定是在调用copystr的时候,修改了str所指的内容。

 

究竟是什么修改了str,难道常量区的内容被莫名修改??

 

回到堆栈的问题上来,我们可以在调试中看各种变量的地址及内存中的信息。

继续看第一段代码,在Test函数的第一行设置断点,运行到此的时候查看p的值,发现是0x0012fedc,打开内存查看器,找到0x0012fedc处,发现附近值全为cc,单步运行一次,此处的值变为了"hello world!"。可见p在被初始化的时候,是从某个地方把"hello world!"搬移到p所在的地址的,并不是p一开始就指向了某个内容区域(前面说的常量区域)。根据这个现象可以推测,p就是放在栈中变量,而"hello world"是存在于一个数据区域(堆区?可堆区是在运行时分配空间的?不大明白这些之间的概念)。

 

为了查找真相,翻下对应的汇编代码:

根据第一行汇编 , "hello world!"串应该存在0x0041573c处,从内存查看器中查看此处内存,确实存在这个串。这段汇编的作用就是通过几组寄存器改变指向"hello world!"串不同的位置,将其搬运到 [ebp-18h]处的栈中(ebp[0x0012fe04]一般用于栈基地址)。

 

通过上面的分析可以知道,p是存在于栈区,指向的内容也在栈中,Test函数返回的是Test函数栈的一个地址,而函数退出后,栈基址ebp发生变化,变为0x0012ff68(Test中为 0x0012fe04),即为进入Test前的栈基址,此时Test函数栈的内存区域已不受保护,随时可能被系统改写内容,这就解释了调用printf或者copystr时,str的内容发生了变化。

既然知道了原理,那就做些改进。一个直接的想法就是将Test函数中的p直接指向常量区域,将其改为static char p[] = "hello world!"即可,产生的汇编代码就一句:mov         eax,offset p (417038h) 。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值