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一样,覆盖的字符串太长了?”古风疑惑的问道。

“不,堆溢出要的就是这样的效果。”老师说道,“我们下面借鉴一下堆栈溢出编程的三个步骤!”