摘要:
原来的版本:http://blog.csdn.net/bigbug_zju/article/details/39892129
原版本中的问题主要在于调试过程中,蛮力的痕迹太重,没有很好地体现常用的调试准则;本文在原版本的基础上,融入参考文献中提及的调试原则,重新审视和操练该问题,希望尽量体现出调试中常用的思维法则。
测试的平台:
1. ubuntu 9; gcc 4.4.1; Gdb 7.0-ubuntu
2. ubuntu系统安装在virtual box 3.2.8虚拟机上;
问题重述:
此处简要地描述下原来的问题,具体细节查看原文,我们希望采用stackoverflow aaaabbbbccccddddeeee中的eeee的值覆盖stackoverflow中overflow到main函数的返回地址,调用overflow返回到main函数时,控制eip,使其中的值为0x63636363;但是实际过程中问题在于eip的值并不是设想的0x63636363,而是0x61616161;
原因何在?
调试过程:
调试原则1:要去看,不是去想;
一开始,我们不能假设性地认为问题就出在overflow返回到main的过程中(既然出问题了,就说明系统的行为跟你想象的差别很大,问题发生在何处都不奇怪)而应该实际地单步运行下看看,看看问题到底在什么地方?通过设置断点,以及单步运行,我们发现eip的控制并不出现在overflow返回到main的过程,而是main函数退出的
过程;
调试原则2:理解系统
根据函数的调用过程,在call前会将当前主函数的下一句地址压栈;在进入函数后,首先执行:push
ebp; mov ebp, esp;
退出函数时,mov esp, ebp; pop ebp。最后调用ret指令时,将call指令压入的下一句地址弹出到eip中。根据上述系统模型,大概需要查看的分支为:
1. main函数返回的地址被修改(也即call main时函数压入的地址),也即esp所指向的返回地址的内容被改变;
2. 还有,返回地址中的内容没有改变,esp所指向的返回地址被改变;
调试原则3:先排除易于验证的分支;
调试原则4:非正常的情况与正常的情况进行比较;
上述的两个调试分支,排除的难以程度相近,我们随便选择1入手.
....to be done.
参考文献:
调试九法:软硬件错误的排查之道,David J. Agans著,赵俐译,人民邮电出版社。