首页
社区
课程
招聘
[原创]极为详细的一次双重释放漏洞调试分析经历
发表于: 2021-8-11 17:21 16310

[原创]极为详细的一次双重释放漏洞调试分析经历

2021-8-11 17:21
16310

本来这周按照计划应该是看CVE-2010-3974 Windows传真封面编辑器的双重释放漏洞的,但是《漏洞战争》这本书中对该漏洞并没有进行什么介绍,漏洞利用方法留在了下一章对于UAF漏洞的介绍中。因此本周文章没有针对具体某个漏洞的介绍,只针对双重释放漏洞本身进行了详细地调试学习。

在我执行书中示例代码生成的程序时,并没有如同书中介绍的那样触发异常,反而出现了程序卡住的情况,自己手动添加了第三次释放之后,程序触发异常。对于这种情况,我根据函数调用栈帧进行了详细地调试,分析了产生上述结果的原因。经过此次调试学习,对于heap的结构以及windows引入的安全机制有了更深的理解,同时也学习到了更多调试内存异常的方法,相信对于之后的漏洞调试分析会有很大帮助。

最初我在理解双重释放这个概念时,注意力主要集中在了指针上,心里一直在想释放两次指针会出什么问题。后来才意识到自己漏洞概念弄混了,双重释放释放的并不是指针,而是指针所指向的空间。

而需要进行释放的空间都是使用类似malloc这类的函数在堆上分配的空间,所以想要了解为什么双重释放会触发异常,就必须对堆结构,以及空间释放时发生的操作有所了解。

我使用下面的代码进行调试分析:

注:在生成Release版本的可执行文件之前,根据参考资料2,设置生成对应的PDB文件,方便调试。

程序在执行后,并没有触发异常,有的时候会直接卡在了最后一步,有的时候会正常执行,所以最后又添加了第三次释放,一定会引发异常。下面看一下这期间究竟发生了什么,导致出现了这三种情况。

直接执行程序,触发异常,windbg打开,显示错误信息:

此时的函数调用信息:

可以看到,当尝试在002d06f8上调用free函数的时候,在RtlpCoalesceFreeBlocks函数处发生了异常。看一下002d06f8这个堆块的信息:

第一个错误信息HEAP 002d0000 (Seg 002d0000) At 002d0678 Error: block list entry corrupted,这个错误信息在这里没什么用,因为现在正在调用HeapFree函数,由于会发生双向链表的链接操作,链表指针的数值可能会发生修改,出现不一致是正常的。

第二个错误信息HEAP 002d0000 (Seg 002d0000) At 002d73d8 Error: invalid block size需要注意一下,从上面的信息可以看到当前的堆块大小为6d60002d0678+6d60=2d73d8,也就是错误信息中的数值。看一下这个地址信息:

这块地址是保留的,再看一下整个堆的信息:

我只截取了前面的一段信息,可以看到整个堆的范围在002d0000002e0000,但是最后有0x5000字节的内存无法使用(committed可以这样理解吗?)。

所以现在基本可以确定002d0678堆块中的size信息是错误的。在回顾一下发生异常的代码:

在尝试向002d73dc写入信息,这个地址是通过esi+eax*8+4计算得到的,实际上就是在通过002d0678堆块的起始地址和大小计算下一个相邻堆块的地址。但是因为size信息有问题,导致计算得到的是一个无法访问的地址,从而出现了异常。

接下来看一下这个size数值是怎么来的。为了调试程序,在程序开头添加__asm int 3,重新启动程序。

直接步进到第二次释放p2之前,然后在RtlpCoalesceFreeBlocks上设置一个断点:

继续运行:

RtlpCoalesceFreeBlocks的函数原型为:

可以根据函数原型对应到栈上的四个参数,其中第三个参数FreeSize是一个指针,真正指向的值为:

看一下306f0处的数据:

大小也是符合的。所以RtlpCoalesceFreeBlocks函数调用确实想要去合并306f0处的堆块,并从所谓的头部获取到了这个堆块的大小作为参数传入了函数中。

接下来跟一下RtlpCoalesceFreeBlocks函数的执行流程:

可以看到执行到这里,得到的要释放的堆块p2的前一个堆块的位置就是代码中分配得到的p1的位置。因为在第一次释放p2的时候,只是把p2和p1、p3合并到一起,只需要修改一些flag值,其他数据并没有改变,所以仍旧能够得到正确的前一个堆块的位置。

接下来一段代码检查前一个堆块是不是空闲的:

之后同样对前一个堆块的头部数据进行了解码,进行了堆块大小的判断,这里不再贴出来。继续看后面,进行了双向链表指针的判断:

接下来有一大段的代码在检查和更新和BlocksIndex有关的内容,这部分知识和Low fragmentation heap有关,具体可以查看参考资料6以及7,我大致看了一下这部分内容,同时调试跟了一下这段代码,还是有一些概念不太清楚,不过大致判断和这次的漏洞分析关系不大,所以下面不再贴出这部分代码,直接步进到相关代码处:

7792430b这个地址是通过静态分析在IDA中获得的。

这里程序检查了上一堆块,即p1这一堆块的flags值,根据参考资料8:

0x01 Indicates that the allocation is being used by the application or the heap manager
0x04 Indicates whether the heap block has a fill pattern associated with it
0x08 Indicates that the heap block was allocated directly from the virtual memory manager
0x10 Indicates that this is the last heap block prior to an uncommitted range

在此程序中,p1堆块的flags值为0,所以上面的跳转都没有执行。

接下来计算并更新堆块合并之后的大小:

这部分操作结束之后,p1堆块的大小增加了原本p2堆块的大小,但是要记得,p2这是第二次释放了,所以相当于p1加上了一个不存在的空间大小。

注意上面最后一行的代码,第三次释放p2的时候,异常就是发生在这里。esi+eax*8+4在尝试计算堆块合并后,p1相邻的下一个堆块的位置(esi+eax*8),并到达其Previous chunk size所在位置(+4),之后用编码后的大小数值更新该位置数据,即更新p1下一堆块中记录的上一堆块大小值。

所以调试到这里,我们知道释放堆块的时候,程序会更新前一相邻堆块的大小为两堆块大小的和,同时根据这个更新后的大小,计算并更新后一堆块中记录的Previous chunk size数据。由于二次释放会导致相邻堆块大小的计算中包含一块不存在的空间,致使计算的大小大于实际大小,如果计算得到的大小超出了可访问内存范围,就会导致更新后一堆块中数据时发生内存访问错误。

虽然知道了发生异常的原因,但是为什么有的时候会出现二次释放p2时卡住的情况呢?继续进行调试:

之后的一段代码程序对p1相邻的下一堆块进行了一些验证,由于这里并没有真的指向一个堆块,所以计算得到的结果也都是不正确的,最后因为验证失败而调用了RtlpLogHeapFailure函数。这部分代码和此次漏洞分析无关,这里不再贴出。

之后程序判断了p1相邻的下一堆块是否为空闲,从而判断是否需要进行合并:

要记得我们这里计算得到的p1相邻的下一堆块是一个不存在的假的堆块,而且它所在的位置一定已经超过了程序一开始自己申请的p1、p2、p3堆块的范围,这部分的数据是不可控的,所以得到的结果有一定随机性。

注:为什么超过了p3的范围?因为经过三次释放,p1、p2、p3已经p3后面的空闲堆块都合并在了一起,此时p1中保存的堆块大小就是这一整块合并之后的堆块大小。但由于p2的二次释放,这一堆块大小又加上了一个数值,所以所谓的p1相邻的下一堆块的位置一定是超过p3的范围的。

这次实验一开始没有跳转,继续往下执行,之后对该下一堆块的头部进行了一些检查,这里的检查比较有意思,它执行了一个这样的操作:next_block->InterceptorValue ^= Heap->Encoding.InterceptorValue;这个操作是在对堆块头部进行解码,所以会改变堆块前四个字节的值,这一点要注意!这里测试的时候失败了,所以调用了RtlpAnalyzeHeapFailure函数。

之后会检查该下一堆块中双向链表指针中的值是否正常,由于并不是一个真正的堆块,所以检查必然会失败(这里成功的可能性基本为零),调用RtlpLogHeapFailure函数。

然后的流程就比较有意思了,这里是一个while循环,程序会再次判断下一堆块是否空闲。

上面文字版的说明可能会比较乱,这里贴一下IDA中获得的伪代码:

也就是说,因为next_block在这里并不是一个真实的堆块,最后验证双向链表指针的时候一定会失败,程序在验证flags数值的时候,指向的堆块一直是同一堆块。如果堆块的前四个字节解码前后的数值在验证flags的阶段一直成功,程序就会陷在这个循环里面。

这就是我在实验的时候,为什么有的时候二次释放p2堆块能够成功执行,有的时候直接卡住的原因。

根据之前的分析,如果二次释放的堆块足够大,那么在二次释放的时候就会发生异常,但是正如在此例中发生的情况一样,p2并不是特别大,所以二次释放的时候并没有触发异常。

第三次释放的时候,如果加上的释放堆块的大小仍旧是p2的大小的话,是不会超出可访问范围的。所以说程序之后一定还进行了一些操作,修改了p2堆块中self size所在位置的数值,导致第三次释放时加上了一个很大的数值。

接下来看一下程序是怎样修改p2堆块中self size所在位置的数值的。

让程序回退到第一次释放p2之前(之前建立了快照),并在306f0处建立一个读写断点:

可以看到在第一次释放p2的时候,p2堆块头部在修改前后的数值变化,self size0xbc3变成了0xf,而0xf就是p2的真实大小(需要*8),所以RtlpFreeHeap函数在77928107这里对于堆块头部的修改,其实就在做一个解码操作(记得前面提到过,系统出于安全考虑,会对堆块头部进行编码)。

接下来继续运行,会遇到一些不太重要的读取过程,然后到达下面这段代码:

可以看到RtlpCoalesceFreeBlocks中第三个参数Freesize是直接从Freeblock的头部,即306f0读取的,也就是读取的解码后的长度。

之后还要在free函数那里设置一个断点,避免在F5的过程中程序直接执行到了下一次p2释放。然后再继续执行,程序知道到达了第二次p2释放:

self size的值会再次被“解码”,因为之前已经是解码之后的值了,这次的解码操作其实相当于做了一次编码,得到了0xbc3

在继续执行之前,看一下这段代码:

在对前四个字节进行了解码操作之后,进行了一个验证:

如果这四个字节解码之后的数据是正常的,验证能够通过。而这里,由于是在进行二次释放,所谓的解码操作其实是在进行编码,得到的结果自然不正常。因此程序会调用RtlpAnalyzeHeapFailure函数。

RtlpAnalyzeHeapFailure函数中,程序又对306f0前四个字节的数值进行了恢复,看一下它的恢复过程:

从上面的代码可以看出,函数不是直接通过编码进行恢复,它首先要确保这四个字节是能够通过验证的,所以它重新设置了SmallTagIndex字段的值,然后再进行编码。这样就能保证之后堆块的前四个字节在解码之后能够通过验证。

修正之后的数值,以及编码后结果为:

这也是为什么在二次释放p2时,得到的self size仍旧是正确的原因。

根据上面的调试流程,p2前四个字节的变化过程:

知道了p2的self size的变化过程,我们就知道为什么第二次释放的时候p2的堆块大小是正常的,而第三次释放的时候p2的堆块大小就变得很大了。

下面总结一下此次双重释放实验触发异常的完整流程:

在进行p2的二次释放时,虽然没有触发异常,但是程序已经访问了本不应该访问的,位于p3之后的空间。在《漏洞战争》中,有提到可以通过“占坑”的方式将已释放的内存填充自己的代码,从而控制程序的执行流程。

如果在代码编写的时候,创建完p3堆块之后,再创建一个堆块p4,且该堆块始终未被释放。那么在二次释放p2的时候,就必然会访问到p4所在的空间,这部分空间内容是可控的(在代码编写阶段,或者加入一个用户输入的功能)。

回顾上面的调试过程,在分析程序为何会在二次释放过程中陷入循环时,由于验证双向链表指针失败,有很多在可控空间(即这里的p4)上面的操作都无法执行。

所以如果精心构造p4的内容,是否可以实现漏洞利用呢?下周会开始看UAF漏洞及其利用方式,双重释放漏洞是UAF漏洞的一个子集,届时就可以知道这样的漏洞究竟是如何实现漏洞利用的了。

 
 
#include <stdio.h>
#include "windows.h"
 
int main (int argc, char *argv[])
{
    void *p1,*p2,*p3;
    char* test_str = "aaaaaaaa";
 
    //__asm int 3
 
    p1 = (char *)malloc(100);   
    printf("Alloc p1:%p\n",p1);
    strncpy(p1, test_str, strlen(test_str));
 
    p2 = (char *)malloc(100);
    printf("Alloc p2:%p\n",p2);
    strncpy(p2, test_str, strlen(test_str));
 
    p3 = (char *)malloc(100);
    printf("Alloc p3:%p\n",p3);
    strncpy(p3, test_str, strlen(test_str));
 
    printf("Free p1\n");
    free(p1);
    printf("Free p3\n");
    free(p3);
    printf("Free p2\n");
    free(p2);
    printf("Double Free p2\n");
    free(p2);
    //printf("Triple Free p2\n");
    //free(p2);
 
    return 0;
}
#include <stdio.h>
#include "windows.h"
 
int main (int argc, char *argv[])
{
    void *p1,*p2,*p3;
    char* test_str = "aaaaaaaa";
 
    //__asm int 3
 
    p1 = (char *)malloc(100);   
    printf("Alloc p1:%p\n",p1);
    strncpy(p1, test_str, strlen(test_str));
 
    p2 = (char *)malloc(100);
    printf("Alloc p2:%p\n",p2);
    strncpy(p2, test_str, strlen(test_str));
 
    p3 = (char *)malloc(100);
    printf("Alloc p3:%p\n",p3);
    strncpy(p3, test_str, strlen(test_str));
 
    printf("Free p1\n");
    free(p1);
    printf("Free p3\n");
    free(p3);
    printf("Free p2\n");
    free(p2);
    printf("Double Free p2\n");
    free(p2);
    //printf("Triple Free p2\n");
    //free(p2);
 
    return 0;
}
 
(b7c.830): Access violation - code c0000005 (!!! second chance !!!)
eax=00000dac ebx=002d0678 ecx=00000665 edx=002d0564 esi=002d0678 edi=002d0000
eip=7792434c esp=0018fdbc ebp=0018fde4 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
ntdll!RtlpCoalesceFreeBlocks+0x47c:
7792434c 66894cc604      mov     word ptr [esi+eax*8+4],cx ds:002b:002d73dc=????
(b7c.830): Access violation - code c0000005 (!!! second chance !!!)
eax=00000dac ebx=002d0678 ecx=00000665 edx=002d0564 esi=002d0678 edi=002d0000
eip=7792434c esp=0018fdbc ebp=0018fde4 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
ntdll!RtlpCoalesceFreeBlocks+0x47c:
7792434c 66894cc604      mov     word ptr [esi+eax*8+4],cx ds:002b:002d73dc=????
0:000> kb
ChildEBP RetAddr  Args to Child             
0018fde4 77923407 0000007f 002d06f0 0018feac ntdll!RtlpCoalesceFreeBlocks+0x47c
0018fedc 779232f2 002d06f0 002d06f8 002d06f8 ntdll!RtlpFreeHeap+0x1f4
0018fefc 772014d1 002d0000 00000000 002d06f8 ntdll!RtlFreeHeap+0x142
0018ff10 004011a7 002d0000 00000000 002d06f8 kernel32!HeapFree+0x14
0018ff2c 00401138 002d06f8 00408030 002d0770 double_free!free+0x66
0018ff48 004014c2 00000001 002d0e38 002d0e90 double_free!main+0x138 [C:\Users\test\Documents\ldzz\double_free\double_free.c @ 33]
0018ff88 77203677 7efde000 0018ffd4 77929d72 double_free!mainCRTStartup+0xb4
0018ff94 77929d72 7efde000 7fa803bd 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77929d45 0040140e 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 0040140e 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> kb
ChildEBP RetAddr  Args to Child             
0018fde4 77923407 0000007f 002d06f0 0018feac ntdll!RtlpCoalesceFreeBlocks+0x47c
0018fedc 779232f2 002d06f0 002d06f8 002d06f8 ntdll!RtlpFreeHeap+0x1f4
0018fefc 772014d1 002d0000 00000000 002d06f8 ntdll!RtlFreeHeap+0x142
0018ff10 004011a7 002d0000 00000000 002d06f8 kernel32!HeapFree+0x14
0018ff2c 00401138 002d06f8 00408030 002d0770 double_free!free+0x66
0018ff48 004014c2 00000001 002d0e38 002d0e90 double_free!main+0x138 [C:\Users\test\Documents\ldzz\double_free\double_free.c @ 33]
0018ff88 77203677 7efde000 0018ffd4 77929d72 double_free!mainCRTStartup+0xb4
0018ff94 77929d72 7efde000 7fa803bd 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77929d45 0040140e 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 0040140e 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> !heap -x 2d06f8
List corrupted: (Blink->Flink = 002d3178) != (Block = 002d0680)
HEAP 002d0000 (Seg 002d0000) At 002d0678 Error: block list entry corrupted
 
HEAP 002d0000 (Seg 002d0000) At 002d73d8 Error: invalid block size
 
Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
-----------------------------------------------------------------------------
002d0678  002d0680  002d0000  002d0000      6d60       108         0  free
0:000> !heap -x 2d06f8
List corrupted: (Blink->Flink = 002d3178) != (Block = 002d0680)
HEAP 002d0000 (Seg 002d0000) At 002d0678 Error: block list entry corrupted
 
HEAP 002d0000 (Seg 002d0000) At 002d73d8 Error: invalid block size
 
Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
-----------------------------------------------------------------------------
002d0678  002d0680  002d0000  002d0000      6d60       108         0  free
 
0:000> !address 2d73d8
 
 
Failed to map Heaps (error 80004005)
Usage:                  <unclassified>
Allocation Base:        002d0000
Base Address:           002d5000
End Address:            002e0000
Region Size:            0000b000
Type:                   00020000    MEM_PRIVATE
State:                  00002000    MEM_RESERVE
Protect:                00000000
0:000> !address 2d73d8
 
 
Failed to map Heaps (error 80004005)
Usage:                  <unclassified>
Allocation Base:        002d0000
Base Address:           002d5000
End Address:            002e0000
Region Size:            0000b000
Type:                   00020000    MEM_PRIVATE
State:                  00002000    MEM_RESERVE
Protect:                00000000
0:000> !heap -a -h 2d0000
Index   Address  Name      Debugging options enabled
  2:   002d0000
    Segment at 002d0000 to 002e0000 (00005000 bytes committed)
    Flags:                00001003
    ForceFlags:           00000001
    Granularity:          8 bytes
    Segment Reserve:      00100000
    Segment Commit:       00002000
    DeCommit Block Thres: 00000200
......
0:000> !heap -a -h 2d0000
Index   Address  Name      Debugging options enabled
  2:   002d0000
    Segment at 002d0000 to 002e0000 (00005000 bytes committed)
    Flags:                00001003
    ForceFlags:           00000001
    Granularity:          8 bytes
    Segment Reserve:      00100000
    Segment Commit:       00002000
    DeCommit Block Thres: 00000200
......
 
(b7c.830): Access violation - code c0000005 (!!! second chance !!!)
eax=00000dac ebx=002d0678 ecx=00000665 edx=002d0564 esi=002d0678 edi=002d0000
eip=7792434c esp=0018fdbc ebp=0018fde4 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
ntdll!RtlpCoalesceFreeBlocks+0x47c:
7792434c 66894cc604      mov     word ptr [esi+eax*8+4],cx ds:002b:002d73dc=????
(b7c.830): Access violation - code c0000005 (!!! second chance !!!)
eax=00000dac ebx=002d0678 ecx=00000665 edx=002d0564 esi=002d0678 edi=002d0000
eip=7792434c esp=0018fdbc ebp=0018fde4 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
ntdll!RtlpCoalesceFreeBlocks+0x47c:
7792434c 66894cc604      mov     word ptr [esi+eax*8+4],cx ds:002b:002d73dc=????
 
0:000> p
eax=000306f8 ebx=7efde000 ecx=0040a110 edx=0008e3b8 esi=00000000 edi=00000000
eip=0040111e esp=0018ff28 ebp=0018ff48 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
double_free!main+0x11e:
0040111e e825000000      call    double_free!free (00401148)
0:000> dd esp L1
0018ff28  000306f8
0:000> bp RtlpCoalesceFreeBlocks
0:000> p
eax=000306f8 ebx=7efde000 ecx=0040a110 edx=0008e3b8 esi=00000000 edi=00000000
eip=0040111e esp=0018ff28 ebp=0018ff48 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
double_free!main+0x11e:
0040111e e825000000      call    double_free!free (00401148)
0:000> dd esp L1
0018ff28  000306f8
0:000> bp RtlpCoalesceFreeBlocks
0:000> g
Breakpoint 0 hit
eax=0018fea0 ebx=00000000 ecx=779bef0f edx=00000000 esi=000306f0 edi=00030000
eip=779230cf esp=0018fddc ebp=0018fed0 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!RtlpCoalesceFreeBlocks:
779230cf 8bff            mov     edi,edi
0:000> dd esp L5
0018fddc  77923407 00030000 000306f0 0018fea0
0018fdec  00000000
0:000> g
Breakpoint 0 hit
eax=0018fea0 ebx=00000000 ecx=779bef0f edx=00000000 esi=000306f0 edi=00030000
eip=779230cf esp=0018fddc ebp=0018fed0 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!RtlpCoalesceFreeBlocks:
779230cf 8bff            mov     edi,edi
0:000> dd esp L5
0018fddc  77923407 00030000 000306f0 0018fea0
0018fdec  00000000
PHEAP_FREE_ENTRY
RtlpCoalesceFreeBlocks(
    IN PHEAP Heap,
    IN PHEAP_FREE_ENTRY FreeBlock,
    IN OUT PULONG FreeSize,
    IN BOOLEAN RemoveFromFreeList
    );
PHEAP_FREE_ENTRY
RtlpCoalesceFreeBlocks(
    IN PHEAP Heap,
    IN PHEAP_FREE_ENTRY FreeBlock,
    IN OUT PULONG FreeSize,
    IN BOOLEAN RemoveFromFreeList
    );
0:000> dd 18fea0 L1
0018fea0  0000000f
0:000> dd 18fea0 L1
0018fea0  0000000f
0:000> dd 306f0 L2
000306f0  d501000f 08000028
0:000> dd 306f0 L2
000306f0  d501000f 08000028
 
ntdll!RtlpCoalesceFreeBlocks:
779230cf 8bff            mov     edi,edi
779230d1 55              push    ebp
779230d2 8bec            mov     ebp,esp
779230d4 83ec1c          sub     esp,1Ch
779230d7 53              push    ebx
779230d8 8b5d0c          mov     ebx,dword ptr [ebp+0Ch]     // 第二个参数306f0 要释放的堆块
779230db 0fb74304        movzx   eax,word ptr [ebx+4]        // 相邻的上一个堆块的大小
779230df 56              push    esi
779230e0 57              push    edi
779230e1 8b7d08          mov     edi,dword ptr [ebp+8]       // 第一个参数 30000
779230e4 0fb74f54        movzx   ecx,word ptr [edi+54h]      // Heap->Encoding.PreviousSize 编码值
779230e8 33c1            xor     eax,ecx                     // Vista之后引入了对heap_entry的编码,这里在进行解码
779230ea c1e003          shl     eax,3                       // size是以8字节为单位的,这里*8,得到字节数0x78
779230ed 8bf3            mov     esi,ebx
779230ef 2bf0            sub     esi,eax                     // 0x306f0-0x78=0x30678,就是p1的位置
ntdll!RtlpCoalesceFreeBlocks:
779230cf 8bff            mov     edi,edi
779230d1 55              push    ebp
779230d2 8bec            mov     ebp,esp
779230d4 83ec1c          sub     esp,1Ch
779230d7 53              push    ebx
779230d8 8b5d0c          mov     ebx,dword ptr [ebp+0Ch]     // 第二个参数306f0 要释放的堆块
779230db 0fb74304        movzx   eax,word ptr [ebx+4]        // 相邻的上一个堆块的大小
779230df 56              push    esi
779230e0 57              push    edi
779230e1 8b7d08          mov     edi,dword ptr [ebp+8]       // 第一个参数 30000
779230e4 0fb74f54        movzx   ecx,word ptr [edi+54h]      // Heap->Encoding.PreviousSize 编码值
779230e8 33c1            xor     eax,ecx                     // Vista之后引入了对heap_entry的编码,这里在进行解码
779230ea c1e003          shl     eax,3                       // size是以8字节为单位的,这里*8,得到字节数0x78
779230ed 8bf3            mov     esi,ebx
779230ef 2bf0            sub     esi,eax                     // 0x306f0-0x78=0x30678,就是p1的位置
 
779230f1 3bf3            cmp     esi,ebx
779230f3 7417            je      ntdll!RtlpCoalesceFreeBlocks+0x481 (7792310c)
779230f5 8b474c          mov     eax,dword ptr [edi+4Ch]         // Heap->EncodeFlagMask
779230f8 8bc8            mov     ecx,eax
779230fa c1e914          shr     ecx,14h
779230fd 224f52          and     cl,byte ptr [edi+52h]           // Heap->Encoding.Flags
77923100 324e02          xor     cl,byte ptr [esi+2]             // pre_block->Flags 获得解码后的前一个堆块的Flags值
77923103 f6c101          test    cl,1                            // 检查是不是空闲
77923106 0f84f5100000    je      ntdll!RtlpCoalesceFreeBlocks+0x41 (77924201)
779230f1 3bf3            cmp     esi,ebx
779230f3 7417            je      ntdll!RtlpCoalesceFreeBlocks+0x481 (7792310c)
779230f5 8b474c          mov     eax,dword ptr [edi+4Ch]         // Heap->EncodeFlagMask
779230f8 8bc8            mov     ecx,eax
779230fa c1e914          shr     ecx,14h
779230fd 224f52          and     cl,byte ptr [edi+52h]           // Heap->Encoding.Flags
77923100 324e02          xor     cl,byte ptr [esi+2]             // pre_block->Flags 获得解码后的前一个堆块的Flags值

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 6
支持
分享
最新回复 (10)
雪    币: 1332
活跃值: (9481)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
2

参考资料中“Heap Corruption: A Case Study”一文链接:

2021-8-11 17:25
0
雪    币: 12016
活跃值: (10399)
能力值: ( LV13,RANK:660 )
在线值:
发帖
回帖
粉丝
3
帖子编辑中显示的内容是正确的,但是发表出来就不对了
https://web.archive.org/web/20160126091336/http://blogs.msdn.com/b/carlos/archive/2008/12/10/heap-corruption-a-case-study.aspx
2021-8-11 17:54
0
雪    币: 12016
活跃值: (10399)
能力值: ( LV13,RANK:660 )
在线值:
发帖
回帖
粉丝
4
erfze 参考资料中“Heap Corruption: A Case Study”一文链接:
因为原文链接已经失效了,所以使用了web archive中的快照链接
2021-8-11 17:57
0
雪    币: 1332
活跃值: (9481)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
5
LarryS 因为原文链接已经失效了,所以使用了web archive中的快照链接
好的
2021-8-12 08:18
0
雪    币: 941
活跃值: (1264)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
确实很详细,谢谢
2021-8-12 09:23
0
雪    币: 15187
活跃值: (16852)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
7
期待下一篇
2021-8-12 09:38
0
雪    币: 6977
活跃值: (1786)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2021-8-12 11:47
0
雪    币: 4934
活跃值: (4653)
能力值: ( LV10,RANK:171 )
在线值:
发帖
回帖
粉丝
9
感谢分享
2021-8-12 14:24
0
雪    币: 86
活跃值: (2026)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
速更,哈哈  期待ing
2021-8-15 19:30
0
雪    币: 409
活跃值: (257)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
2021-8-28 22:12
0
游客
登录 | 注册 方可回帖
返回
//