首先得会内存、寄存器还有程序运行的规则。
存储知识:
文件地址(File Offset):数据在PE文件中的地址,文件在磁盘上存放时相对于文件开头的偏移;
虚拟内存地址:每个进程都有的4G虚拟空间;
物理内存地址;
这三个地址要层层映射
内存:
代码区:存放二进制代码
数据区:存储全局变量
堆区:动态内存空间(还没太明白用途)
栈区:存放函数调用关系(缓冲区溢出就在这里发生)
重点研究栈的结构:
栈帧:每个函数有自己的栈帧,只有被调用的函数才会在系统栈开辟栈帧,调用完毕将弹出栈帧
两个寄存器(用于标示当前正在执行的函数的栈帧):
ebp:指向栈顶的底部
esp:指向栈顶的顶部
发生函数调用时栈帧的创建过程:
参数入栈
返回地址入栈
保存当前栈帧状态,也就是主调函数栈帧的ebp和esp,似乎一般情况下只要ebp就行
把esp寄存器内容装入ebp寄存器,即创建被调用函数的栈帧作为当前栈帧
根据被调用函数需要的变量情况开辟一定大小的空间,用esp减去空间就得到当前栈帧的栈顶(从栈底到栈顶内存地址从高到底)
明白了这些就可以开始缓冲区溢出小实验了:
#include<stdio.h> void hack() { printf("hello"); //_exit(0); return; } int main() { int a[0]; a[3]=0x004016b6; return 0; }
看了下图就明白了
我们知道数组是从a[0]的位置开始向后移动的,那么a[3]的位置(如图的话应该是a[2]才对,我猜想应该是我的电脑不仅存了上个函数的ebp还存了esp所以就是a[3])正好是返回地址,但是给a[3]赋值为hack()函数的起始地址那么main函数就会跳转到hack()的地址执行hack函数。注意main函数也有返回地址。
hack()函数的地址先通过正常调用一次然后用IDA工具很容易就找到了。反汇编软件爆破就要用到上面的三个存储地址的映射关系。
没想到写得这么累。
大概先这样。
原文地址:http://blog.csdn.net/ac_0_summer/article/details/45567349