请填空,使程序运行结果为:打印"why u r here?!"
虚拟机环境以及IDE
VMware16
win xp sp3
vc6
题目代码解析
#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
void why_here(void) //我们需要让代码跑这个函数
{
printf("why u r here?!\n");
exit(0);
}
void f() //主函数跳转到这
{
int buff[1];// 声明buff是整型数组,空间大小1,末尾为buff[0]
int *p=buff;//声明p指针,整型,指向buff,p的值其实就是buff的地址
_____= (int)why_here;//把函数why_here的地址转化为整型赋给(填空)
}
int main(int argc, char* argv[])//主函数
{
f();//调用函数f
return 0;
}
函数f()的栈帧情况
以下是栈帧的逻辑图表示
从图中可以看到局部变量区的位置和返回地址的位置
以下是vc6中的地址展示情况
从低地址到高地址,int型占据4个字节,也就是图中红框所展示的局部变量
由于p指针被指到了buff,所以对p的操作地址和buff是一样的并没有多一个空间列给p
我们可以简单理解为:
要想执行why_here函数,就要使f函数的栈帧前的返回地址为why_here
通过对buff的数组越界可以达到这一点,即buff的开头地址也就是p往高地址走4个字节后到达ebp再走4个字节后为返回地址,即
p的地址+8=buff[2](每个int单位为4个字节)
所以可知填空为buff[2],或者p[2]
实验步骤
1. 打开虚拟机win—xp
2.打开vc6新建工程 win32 console application
完成,确定。
3.打开main()把代码复制进去
#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
void why_here(void)
{
int a[1]={10};
printf("why u r here?!\n");
exit(0);
}
void f()
{
int buff[1]={1};
int *p=buff;
p[2]= (int)why_here;
}
int main(int argc, char* argv[])
{
f();
return 0;
}
与题目不同的代码是调试时监督地址位置以及空间用的
4.设置断点(F9)运行调试
调试界面
第一次进入调试界面
第一次进入调试界面只会出现这个框,把它拖到菜单栏下面就固定在栏下了
点开图中红框所示界面即可看见调试图中的各个窗口
打开调试界面以后点击以下红框可进行代码执行
下一步
下一步
下一步
28 FF 12 00要读为0012ff28
打开汇编预览
下一步,下一步
注意该位置,p[2]的值十进制并不等于(int)why_here,这部分在下面会有解释
现在我们可以看到,返回地址部分变为了
0F 10 40 00 也就是 0040100F
然后我们再点击跳出该空间
我们看到,函数确实按照返回值那样跳到了0040100F位置,eip指的是当前执行代码地址
可以看到该地址执行的汇编命令为jmp why_here(00401030),意思是跳转到00401030
于是,我们再跳转出该空间就会来到函数why_here(00401030),这也解释了为什么上面p[2]=4198415,而为什么不是419448,因为它真正的跳转中转在0040100F。
代码来到了00401030,下一步…以后已经不用解释了,代码已经来到了why_here,作业到此结束。