当前位置:   article > 正文

DUMP文件分析6:简单的堆破坏示例_为什么dump 不能使用标记堆

为什么dump 不能使用标记堆

本节,我们来看一个简单的堆破坏示例,程序依旧来自前面的示例,Crash Me!按钮的消息函数如下:

void Cdump3Dlg::OnBnClickedButton1()
{
    int* a = new int[1000];

    for( int i = 0; i < 1005; i++ )
        a[i] = i;

    printf("%d\n", a[0]);

    delete [] a;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我们让new分配的数组访问越界,看看会产生什么结果。本节采用程序的方式来采集DUMP,同时,堆分析需要比较多的信息,因此,MiniDumpWriteDump函数中的Minidump类型写为MiniDumpWithFullMemory,而不是原来的MiniDumpNormal。Visual Studio中的Debug模式下使用的堆为调试堆,具有额外的检查功能,可以检查出堆破坏。我们使用Release模式编译。运行程序,程序出错,并自动保存了mini.dmp文件:

拖入Windbg中,输入 !analyze -v 自动分析。先看看出错的位置及异常信息:

显示出错在RtlpAllocateHeap函数中,那必然是调用new或malloc时出错。异常代码为c0000005,非法访问,在RtlpAllocateHeap内部产生了非法访问?我们再来看看栈回溯:

显示是在OnBnClickedButton1中调用printf函数时出的错。看看我们的代码:
printf(“%d\n”, a[0]);
这句也能出错?没有任何越界访问啊?再看看栈回溯,大概是这个样子的:

也就是说,是printf内部调用了malloc导致出错。那么我们上一节说过,库函数使用VC运行时的堆_crtheap,任何时候这个堆被破坏,后续对该堆的操作都可能会出错,这个示例就是典型的这种情况。所以不要再怀疑Visual Studio为什么printf函数也会崩溃了。

使用Windbg的 !heap指令来查看一下:

Windbg检查到堆错误,错误的地址为0073c4b8,进程中有8个堆,出错的是第4个。你可以加 -h选项来列出所有的堆:

4号堆已经使用了两个段。查看4号堆,还可以获得更多的信息:

来看看错误提示消息,这很有意思:
PreviousSize field does not match Size field in previous entry
Entry->PreviousSize == 0x3e8
PreviousEntry->Size == 0x2a2
PreviousSize 和Size 均位于结构 HEAP_ENTRY中,每个小的堆块前面都是一个HEAP_ENTRY结构,用来保存该块的信息:

HEAP_ENTRY结构中有一些重要的字段:

0:000> dt _HEAP_ENTRY
ntdll!_HEAP_ENTRY
   +0x000 Size             : Uint2B    // 以粒度表示的块大小,不包括本结构
   +0x002 Flags            : UChar     // 堆块的状态
   +0x003 SmallTagIndex    : UChar
   +0x000 SubSegmentCode   : Ptr32 Void
   +0x004 PreviousSize     : Uint2B     // 前一个堆块的大小
   +0x006 SegmentOffset    : UChar
   +0x006 LFHFlags         : UChar
   +0x007 UnusedBytes      : UChar    // 用户数据区的未使用字节数
   +0x000 FunctionIndex    : Uint2B
   +0x002 ContextValue     : Uint2B
   +0x000 InterceptorValue : Uint4B
   +0x004 UnusedBytesLength : Uint2B
   +0x006 EntryOffset      : UChar
   +0x007 ExtendedBlockSignature : UChar
   +0x000 Code1            : Uint4B
   +0x004 Code2            : Uint2B
   +0x006 Code3            : UChar
   +0x007 Code4            : UChar
   +0x000 AgregateCode     : Uint8B
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

那么错误的意思就是当前块的HEAP_ENTRY结构中保存的前一个堆块的大小(PreviousSize)与前一个堆块的实际大小(Size)不一致。这说明前一个堆块发生了溢出,修改了后一个堆块的HEAP_ENTRY结构。这实际上就是堆破坏的根本原因,堆通过一系列结构来管理,一旦对堆的操作越界,破坏了这些用来管理堆的结构,堆就无法再正常工作了。读者还可以继续跟踪实际的堆块(Chunk),我就不再继续了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/106316
推荐阅读
相关标签
  

闽ICP备14008679号