4.2.1 有问题的例子
“我们看一个简单的有堆溢出问题的程序heapvul1.c(光盘有收录)。”
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
char mybuf[] = "ww0830";
int main (int argc, char *argv[])
{
HANDLE hHeap;
char *buf1, *buf2;
//我们自己建立一个HEAP
hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0xfffff);
printf("mybuf addr = %p\n",mybuf);
//动态分配buf1
buf1 = HeapAlloc(hHeap, 0, 200);
strcpy(buf1,mybuf);
printf("buf1 = %s\n",buf1);
//动态分配buf2
buf2 = HeapAlloc(hHeap, 0, 16);
HeapFree(hHeap, 0, buf1);
HeapFree(hHeap, 0, buf2);
return 0;
}
“我给大家大致解释一下:”
“hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0xfffff);”是建立一个堆,以免破坏进程默认HEAP;
“buf1 = HeapAlloc(hHeap, 0, 200);
”是动态分配200字节的buf1;
“strcpy(buf1,mybuf);
”是把mybuf数组的内容拷贝给buf1;
“buf2 = HeapAlloc(hHeap, 0, 16);
”表示接着分配buf2;
“HeapFree(hHeap, 0, buf1); HeapFree(hHeap, 0, buf2);
”表示最后把buf1和buf2释放掉后就退出。
“我们执行一下试试,使用VC的RELEASE方式编译,并在命令行下运行,程序就会打印出mybuf地址和buf1内容,然后退出。”
小知识:
在VC下可以生成DEBUG版本和RELEASE版本程序。DEBUG版被称为调试版,RELEASE版被称为发布版。DEBUG版程序中,会有一些用于调试的信息,所以会比RELEASE版程序大很多;而且有一些内部处理和分配过程,比如堆的分配,两者也不同。
“DEBUG版的程序与实际运行程序的内存结构是不同的,所以刚才那个程序要用VC按照RELEASE方式编译,并在命令行下运行它,不要在MSDEV中调试运行。”
“在VC下生成RELEASE版的方法是:选择菜单栏‘编译’→‘放置可远程配置’,然后在弹出的‘活动工程配置’中选择‘Win32 RELEASE’,这样,生成的程序就会在Release目录下,并且是发布版本。”
“也可以在工具栏的‘Select Active Configurature’框中直接选择生成Release版,如图4-5。”
“在mybuf数组很小的时候,程序没有任何问题,我们稍微改变下程序,只是加长mybuf的长度,变为240个A,具体代码参看heapvul2.c(光盘有收录)。”
“我们重新生成RELEASE版的程序,在命令行下运行它。效果如图4-6。”
“哦!出现报错对话框了!”大家说道!
“内容为 "0x77fcb3f5"指令引用的"0x41414141"内存。该内存不能为"written" 。‘0x41’就是大写字母A的16进制码。”
“不过这里报的是‘written’错误啊!莫非和Foxmail一样,覆盖的字符串太长了?”古风疑惑的问道。
“不,堆溢出要的就是这样的效果。”老师说道,“我们下面借鉴一下堆栈溢出编程的三个步骤!”