先来说下啥是缓冲区溢出。
缓冲区:把它理解成一快地方(内存空间)不管这快地方内是否有东西。
溢出:把它理解成水满了,溢出来了(这里指缓冲区)

那么其实就是,有一快空间,里面的东西太多了,溢出来了。

那么如何去实现他呢?

我们写程序的时候,长期调用某些函数,或称子程序。
子程序可以理解成单独的一个过程(有他独特的代码,独特的空间,和可以认为是自有的数据)
那么其中的空间就是我们要照顾的重点了。(这空间指的就是缓冲区)
为了保证每个子程序都能自己去处理某些事情,那么他必须要用到一些数据吧。
这个数据存放在那里呢?  难道我们必须去了解这个子程序的一切,并且每次调用的时候都把数据在自己的代码块定义好? 非也!
显然,我们每次调用子程序的时候除了传递参数以外,其余的功能他都可以实现了。
那么到底他把数据存在哪了呢?
答案是:“堆栈段”
堆栈段:“一个特殊的段,可读可写,esp和ebp做寻址”
也就是说,esp和ebp指向了这个段
那么这个段和我们溢出有什么关系啊。
请看:
我们调用一个子程序是这样写的
push   1
push   1
call     XXX        ;关键在这里
add    esp,8

XXX:                 ;call相当于把eip的值push进去然后jmp到XXX
push  ebp
mov   ebp,esp
sub    esp,???   ;???代表了一个数值,表示让esp栈顶指针减XXX,就相当于开辟了一个空间。
在这里要补一下汇编知识了,push 一下=esp-4(32位是-4Byte)那么pop就=esp+4了
我们存放数据就是存放到了esp-4Byte的地方esp esp+1 esp+2 esp+3存放的是当前esp指向的值。也就是说push后esp的值+了4  怎么去把这个4Byte的数据给拿出来呢?
相信在esp存值和取值上迷倒了许多人的脑袋!呵呵
其实让上面的思考方式是不对的,我们要想存和取的顺序
push  123
[00101000]esp       ;就是在这个地方存入了数据4Byte的数据
[00101004]esp+4   ;这里结束了,然后继续push继续存
[00101008]esp+4
pop   eax
[00101000]esp-4
[00101004]esp       ;现在的esp就是刚才的esp+4(这里就可以看出来,是逐一字节存放的)
[00101008]esp+4
现在就可以明确的看出来,这个值的怎么拿和放的。
当取出来后,低位字节存放到寄存器低位,高位字节存放到寄存器高位。

现在来正式进入:

push  XX
push  XX
call    XXX
add  esp,8
XXX:
push  ebp
mov   esp,ebp
sub    esp,128d
pushad

popad
mov  esp,ebp
pop   ebp
ret                     ;重点就在这里了

ret可以理解jmp到esp-4指向的值
那么也就是说改变了esp-4指向的值就可以改变程序的返回后地址。
说到这里就很明显了
我们很能联想到。
局部变量是如何分配的。
假如我定义了一个局部变量
他存放到了ebp-4这个地方
假如我定义了n个局部变量呢?
那么就把应该还原的寄存器值给覆盖了,这个不允许的。
所以我们只能从上往下来分配,那么也就是说
当我分配的太多。最后就把ebp+4这地方的数据给覆盖了
程序返回地址就成了这个地方

原理说通俗点就是:
你告诉我回去哪里,告诉后却不管我了。(如果你最后在告诉我一便)
你告诉我后又有人来告诉我了,我反正就是谁告诉我我就听谁的。(最后一个告诉的我听他的)
呵呵,我反正不管回去的地方是那里,有路就行了。