@rg070836rg
2016-11-01T07:15:51.000000Z
字数 964
阅读 2004
网络安全
函数的局部变量在栈中,一个挨着一个排列,如果有缓冲区,那么可能 就存在数组越界的可能,比如破坏相邻的变量值,或者破坏EBP,返回地址等。
#include "stdafx.h"#include <iostream>using namespace std;#define PASSWORD "12345"int verify(char * psw){int auth;char buffer[8];auth = strcmp(PASSWORD, psw);strcpy(buffer, psw);//缓冲区溢出点return auth;}int main(int argc, _TCHAR* argv[]){int flag = 0;char psw[1024];while (1){cout << "输入密码" << endl;cin >> psw;flag = verify(psw);if (flag){cout << "密码错误" << endl;}else{cout << "验证成功" << endl;}}return 0;}
我们来观察auth的地址以及buffer的地址
&auth:0x0019FAC8

&buffer:0x0019FAC0


很容易发现auth刚好在buffer的下方,这样我们可以利用这个缓冲区,来替换auth的内容。
我们试着输入abcdefghijk:
在执行过strcpy之后,我们观察内存:

很容易发现,0x0019FAC8 中间的值被修改了。
那我们只要构造,让溢出的时候,让其为0即可

测试结果:

这是函数栈帧的起始点与结束部分

我们通过寄存器可以看到 EBP的地址:
EBP = 0019FACC

EBP上下文:
我们发现EBP在auth下方记下来一行就是我们函数的返回地址
这边记录的是我们的返回地址,对应着main函数(调用者)的EIP寄存器值。
main函数(调用者)

那么我们只需要修改EBP下方的内容,就可以重新定位返回点,来执行其他的代码,所以我们只需要找到一个有效的指令地址,就可以跳转到任意地方去执行代码。
从反汇编中,我们找到 验证成功的地址,我们只需要,将这个地址给构造进输入,那么就可以跳过验证,直接进入main中的else分支。

这边由于某些地址对应的ASSIC字符,比较难输入(需要从文本读入比较方便),所以不去实验了。
