转:https://bbs.pediy.com/thread-224136.htm

准备刷漏洞战争中的堆溢出部分,但是对于堆的了解较少,在这里记录一下关于堆的学习记录,有错误请各位大大拍砖

参考:

  • 《软件调试》
  • 《0day安全 软件漏洞分析技术》

win32下的堆管理系统:

1. win32堆管理器

win32堆管理器由NTDLL.dll实现,目的是为用户态的应用程序提供内存服务,从实现角度上来讲,内核态的池管理器和用户态的win32堆管理器默用的是同一套基础代码,它们以运行时的方式存在于ntdll.dll和ntosknrl.exe模块中。

2. CRT堆管理器

  • CRT由C运行时库创建,CRT创建的堆有三种模式,分别是SBH,ODLSBH和System Heap模式,CRT运行时库选择一种模式创建相应的堆。
  • 对于SBH和OLDSBH模式来说,CRT堆会从堆管理器中批发大块的内存,然后分割成小块的内存供程序使用,对于系统模式,CRT堆只是将堆分配请求转发给它基于的win32堆。因此处于系统模式的CRT堆只是对win32堆的简单封装。

win32堆

1.体系结构

应用程序通过堆管理器提供的接口来分配或者是释放内存,整个堆管理器由堆管理api,前端堆,后端堆组成。在处理内存的分配和释放的时候,前端堆先做处理,前端堆有三种选择:none,预读列表(快表,lookaside-list),LFH(低碎片堆)。

2.堆的内部结构

和堆相关的数据结构主要有以下几个:

  • _HEAP
  • _HEAP_SEGMENT
  • _HEAP_ENTRY
  • _HEAP_FREE_ENTRY
    堆管理器通过_HEAP来记录和维护堆的管理信息,在_HEAP结构中,可能存在一个或者若干个_HEAP_SEGMENT的信息。在我们创建堆时,堆管理器必然会像操作系统申请一块内存空间,那么申请的内存大小和这段内存空间的描述信息就由_HEAP_SEGMENT记录。在每一个_HEAP_SEGMENT结构中,可能存在若干个_HEAP_ENTRY和_HEAP_FREE_ENTRY结构,其中_HEAP_ENTRY和_HEAP_FREE_ENTRY都是对堆块的描述,只不过_HEAP_FREE_ENTRY描述的是空闲的堆快结构,而由_HEAP_ENTRY描述的不一定都是空闲的堆块。
    其中_HEAP_ENTRY和_HEAP_FREE_ENTRY的结构体如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0:000> dt _HEAP_ENTRY
ntdll!_HEAP_ENTRY
   +0x000 Size             : Uint2B
   +0x002 PreviousSize     : Uint2B
   +0x000 SubSegmentCode   : Ptr32 Void
   +0x004 SmallTagIndex    : UChar
   +0x005 Flags            : UChar
   +0x006 UnusedBytes      : UChar
   +0x007 SegmentIndex     : UChar
 
0:000> dt ntdll!_HEAP_FREE_ENTRY
   +0x000 Size             : Uint2B
   +0x002 PreviousSize     : Uint2B
   +0x000 SubSegmentCode   : Ptr32 Void
   +0x004 SmallTagIndex    : UChar
   +0x005 Flags            : UChar
   +0x006 UnusedBytes      : UChar
   +0x007 SegmentIndex     : UChar
   +0x008 FreeList         : _LIST_ENTRY
  • ps:上面两个结构体中比较坑的是,在xp sp3下,通过windbg查看_HEAP_ENTRY和_HEAP_FREE_ENTRY结构体中的第四个字段为SmallTagIndex,但实际上这个字段应该是安全cookie,算法如下:_HEAP._HEAP_ENTRY.cookie=_HEAP_ENTRY.cookie^((BYTE)&_HEAP_ENTRY/8)
  • 在win7下,直接用_HEAP_ENTRY和_HEAP_FREE_ENTRY查看数据,会存在问题,需要用_HEAP.ENCODING字段进行解密。

_HEAP结构

windows xp下的_HEAP结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
0:000> dt  ntdll!_HEAP 003b0000                
   +0x000 Entry            : _HEAP_ENTRY
   +0x008 Signature        : 0xeeffeeff ;heap结构签名
   +0x00c Flags            : 0x50001060 ;堆属性
   +0x010 ForceFlags       : 0x40000060 ;
   +0x014 VirtualMemoryThreshold : 0xfe00;最大堆块大小
   +0x018 SegmentReserve   : 0x100000
   +0x01c SegmentCommit    : 0x2000 
   +0x020 DeCommitFreeBlockThreshold : 0x200
   +0x024 DeCommitTotalFreeThreshold : 0x2000
   +0x028 TotalFreeSize    : 0x130;空闲块总大小,以粒度为单位
   +0x02c MaximumAllocationSize : 0x7ffdefff;堆可分配的最大内存
   +0x030 ProcessHeapsListIndex : 6;堆在peb.processheaps数组中的索引+1
   +0x032 HeaderValidateLength : 0x608
   +0x034 HeaderValidateCopy : (null)
   +0x038 NextAvailableTagIndex : 0
   +0x03a MaximumTagIndex  : 0
   +0x03c TagEntries       : (null)
   +0x040 UCRSegments      : (null)
   +0x044 UnusedUnCommittedRanges : 0x003b0598 _HEAP_UNCOMMMTTED_RANGE
   +0x048 AlignRound       : 0x17
   +0x04c AlignMask        : 0xfffffff8
   +0x050 VirtualAllocdBlocks : _LIST_ENTRY [ 0x3b0050 - 0x3b0050 ]
   +0x058 Segments         : [640x003b0640 _HEAP_SEGMENT
   +0x158 u                : __unnamed
   +0x168 u2               : __unnamed
   +0x16a AllocatorBackTraceIndex : 0
   +0x16c NonDedicatedListLength : 1
   +0x170 LargeBlocksIndex : (null)
   +0x174 PseudoTagEntries : (null)
   +0x178 FreeLists        : [128] _LIST_ENTRY [ 0x3b0688 - 0x3b0688 ];空闲块
   +0x578 LockVariable     : 0x003b0608 _HEAP_LOCK
   +0x57c CommitRoutine    : (null)
   +0x580 FrontEndHeap     : (null)
   +0x584 FrontHeapLockCount : 0
   +0x586 FrontEndHeapType : 0 ''
   +0x587 LastSegmentIndex : 0 ''

在这个结构体中,FreeLists是一个由128个LIST_ENTRY结构体组成的结构体数组,在调用HeapCreate时,Freelists[0]指向尾块,尾块也就是堆刚创建出时最大的一个空闲块,数组中的其他元素指向自己。

3.创建进程时操作系统为进程创建的默认堆:

ntdll!KiUserApcDispather->ntdll!_LdrpInitialize->ntdll!LdrplInitializeProcess->ntdll!RtlCreateHeap,创建好的堆的句柄回保存在PEB结构的ProcessHeap字段中,PEB中关于堆的字段如下:

1
2
3
4
5
6
7
0:000> dt ntdll!_PEB
    +0x018 ProcessHeap      : Ptr32 Void //堆句柄
    +0x078 HeapSegmentReserve : Uint4B   //默认堆的保留大小:1MB
    +0x07c HeapSegmentCommit : Uint4B    //默认堆的提交大小:8kb
    +0x088 NumberOfHeaps    : Uint4B     //进程中堆的总数
    +0x08c MaximumNumberOfHeaps : Uint4B //ProcessHeaps数组中数组元素的个数
    +0x090 ProcessHeaps     : Ptr32 Ptr32 Void//这个数组用来保存进程中创建的堆的句柄

4.私有堆:

创建:

可以通过HeapCreate这个api来创建属于进程的私有堆,这个api实际上回去调用RtlCreateHeap函数,创建完毕之后会将创建好的堆句柄保存到peb结构中。HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize, SIZE_T dwMaximumSize)这个api中,flOptions下面三个可选项:

  • HEAP_CREATE_ENABLE_EXECUTE 允许执行堆中的代码,也就是这时创建出的堆具有可执行属性。
  • HEAP_GENERATE_EXCEPTIONS 使用异常来报告HeapAlloc和HeapReAlloc的错误而不是通过返回NULL。
  • HEAP_NO_SERIALIZE 当堆函数访问这个堆时,不需要进行串行化控制。这么做可以提高操作堆的速度,但是在多线程同时操作堆时,可能出现问题。当创建堆时指定这个参数时,不能启用低碎片堆(LFH)。

在windbg中可以使用!heap -h指令来查看进程中的所有堆。!heap -h的查询结果也就是peb.ProcessHeaps中的值。

销毁:

HeapDestory->ntdll!RtlDestroyHeap->NtFreeVirtualMemory。
ntdll!RtlDestroyHeap会将PEB堆列表中的堆要销毁堆的堆句柄移除掉,然后通过NtFreeVirtualMemory函数向内存管理器归还内存。
应用程序不应该也不许销毁默认堆,当进程退出和销毁进程对象时,系统都会调用MnCleanProcessSpace函数。

堆内存的申请和释放

通过HeapAlloc这个api可以从堆中分配空间出来,LPVOID WINAPI HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes),dwFlags有下面几个选项:

  • HEAP_GENERATE_EXCEPTIONS 系统通过返回异常而不是返回NULL来报告错误
  • HEAP_NO_SERIALIZE 不对堆进行串行话控制。
  • HEAP_ZERO_MEMORY 分配的内存将被初始化为0。

ps:指定这些值中的任何值将覆盖使用HeapCreate创建堆时指定的对应值 。

 

也可以使用malloc,calloc或者是new运算符来从堆中分配内存,上面提到CRT堆有三种模式,大多数情况下,运行时库都会选择系统模式,此时CRT堆建立在win32堆之上。

 

通过HeapFree这个api可以从释放HeapAlloc申请处的内存空间,free或者是delete最终都会跳到这个api上来释放内存。

winxp 堆内存释放和合并-空闲双向链表:

实验代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <windows.h>
main()
{
    HLOCAL h1,h2,h3,h4,h5,h6;
    HANDLE hp;
    hp = HeapCreate(0,0x1000,0x10000);
    getchar();
    __asm int 3
 
    h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,3);
    h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,5);
    h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,6);
    h4 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h5 = HeapAlloc(hp,HEAP_ZERO_MEMORY,19);
    h6 = HeapAlloc(hp,HEAP_ZERO_MEMORY,24);
 
    HeapFree(hp,0,h1); //free to freelist[2]
    HeapFree(hp,0,h3); //free to freelist[2]
    HeapFree(hp,0,h5); //free to freelist[4]
 
    HeapFree(hp,0,h4); //coalese h3,h4,h5,link the large block to freelist[8]
    return 0;
}

执行程序之后用windbg附加,然后f5,断到int 3,在windbg中查看空闲表

1
2
3
4
5
0:000>dd 0x003a0000+0x178
003a0178  003a0688 003a0688 003a0180 003a0180
003a0188  003a0188 003a0188 003a0190 003a0190
003a0198  003a0198 003a0198 003a01a0 003a01a0
003a01a8  003a01a8 003a01a8 003a01b0 003a01b0

Heap.FreeLists[0]的flink和blink分别都指向0x003a0688.通过!heap -a 003a0000查到的结果,我们来看分配到的堆块结构,在windbg中输入
!heap -x 003a0640或者是dt ntdll!_HEAP_ENTRY来查看堆结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
0:000> !heap -003a0640
Entry    User      Heap      Segment      Size  PrevSize  Unused    Flags
-----------------------------------------------------------------------------
003a0640  003a0648  003a0000  003a0640        40      640        0  busy
 
0:000> dt ntdll!_HEAP_ENTRY 003a0640
  +0x000 Size            : 8
  +0x002 PreviousSize    : 0xc8
  +0x000 SubSegmentCode  : 0x00c80008
  +0x004 SmallTagIndex    : 0 ''
  +0x005 Flags            : 0x1 ''
  +0x006 UnusedBytes      : 0 ''
  +0x007 SegmentIndex    : 0 '

其中_HEAP_ENTRY.Size为堆块的大小/堆块分配粒度,堆块分配粒度一般都为8,可以用!heap -v 堆基址来查看
然后单步执行完 h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,3),观察空闲块的变化

1
2
3
4
5
0:000> dd 0x003a0000+0x178
003a0178  003a0698 003a0698 003a0180 003a0180
003a0188  003a0188 003a0188 003a0190 003a0190
003a0198  003a0198 003a0198 003a01a0 003a01a0
003a01a8  003a01a8 003a01a8 003a01b0 003a01b0

此时Heap.FreeLists[0]的flink和blink分别都指向0x003a0698,在windbg中输入!heap -x 0x003a0698或者是dt ntdll!_HEAP_FREE_ENTRY 0x003a0698-8来查看堆结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0:000> !heap -003a0698
Entry    User      Heap      Segment      Size  PrevSize  Unused    Flags
-----------------------------------------------------------------------------
003a0690  003a0698  003a0000  003a0640      970        10        0  free last
 
0:000> dt ntdll!_HEAP_FREE_ENTRY 003a0698-8
  +0x000 Size            : 0x12e
  +0x002 PreviousSize    : 2
  +0x000 SubSegmentCode  : 0x0002012e
  +0x004 SmallTagIndex    : 0 ''
  +0x005 Flags            : 0x10 ''
  +0x006 UnusedBytes      : 0 ''
  +0x007 SegmentIndex    : 0 ''
  +0x008 FreeList        : _LIST_ENTRY [ 0x3a0178 - 0x3a0178 ]

在_HEAP_FREE_ENTRY中多了一个LIST_ENTRY成员,而这个成员的flink和blink都只想freelist[0]。单步执行完HeapFree(hp,0,h1);在windbg中观察下内存的变化:

1
2
3
4
5
6
7
8
0:000> dd 003a0000+0x178
003a0178  003a0708 003a0708 003a0180 003a0180
003a0188  003a0688 003a0688 003a0190 003a0190
003a0198  003a0198 003a0198 003a01a0 003a01a0
003a01a8  003a01a8 003a01a8 003a01b0 003a01b0
003a01b8  003a01b8 003a01b8 003a01c0 003a01c0
003a01c8  003a01c8 003a01c8 003a01d0 003a01d0
003a01d8  003a01d8 003a01d8 003a01e0 003a01e0

可以看到Heap.FreeLists[2]成员的flink和blink分别都指向了0x003a0688,而在此之前,Heap.FreeLists[2]的两个成员都指向自己。单步执行完HeapFree(hp,0,h5)观察下内存结构

1
2
3
4
5
6
0:000> dd 003a0000+0x178
003a0178  003a0708 003a0708 003a0180 003a0180
003a0188  003a0688 003a06a8 003a0190 003a0190
003a0198  003a06c8 003a06c8 003a01a0 003a01a0
003a01a8  003a01a8 003a01a8 003a01b0 003a01b0
003a01b8  003a01b8 003a01b8 003a01c0 003a01c0

FreeList[0].flink和blink都指向最后一个空闲块003a0708,FreeList[2].flink指向第一次释放的堆块,FreeList[2].blink指向第二次释放的堆块。在windbg中查看下这两个空闲块的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0:000> dt ntdll!_HEAP_FREE_ENTRY 003a0688-8
  +0x000 Size            : 2
  +0x002 PreviousSize    : 8
  +0x000 SubSegmentCode  : 0x00080002
  +0x004 SmallTagIndex    : 0xcb ''
  +0x005 Flags            : 0 ''
  +0x006 UnusedBytes      : 0xd ''
  +0x007 SegmentIndex    : 0 ''
  +0x008 FreeList        : _LIST_ENTRY [ 0x3a06a8 - 0x3a0188 ]
0:000> dt ntdll!_HEAP_FREE_ENTRY 003a06a8-8
  +0x000 Size            : 2
  +0x002 PreviousSize    : 2
  +0x000 SubSegmentCode  : 0x00020002
  +0x004 SmallTagIndex    : 0xcf ''
  +0x005 Flags            : 0 ''
  +0x006 UnusedBytes      : 0xa ''
  +0x007 SegmentIndex    : 0 ''
  +0x008 FreeList        : _LIST_ENTRY [ 0x3a0188 - 0x3a0688 ]

观察空闲块和Freelist表结构,我们可以得出结论:每个空闲块的前向指针指向前一个空闲块,第一个空闲块的前向指针指向相应的freelist头,每一个空闲块的后向指针指向下一个空闲块,最后一个空闲块的后向指针指向相应的freelist头,而freelist头的前向指针指向最后一个空闲块,freelist头的后向指针指向第一个空闲块,这样就构成了一个双循环链表。

 

单步执行完HeapFree(hp,0,h4); //coalese h3,h4,h5,link the large block to freelist[8],观察下空闲块的结构:

1
2
3
4
5
6
7
8
9
0:000> dd 003a0000+0x178
003a0178  003a0708 003a0708 003a0180 003a0180
003a0188  003a0688 003a0688 003a0190 003a0190
003a0198  003a0198 003a0198 003a01a0 003a01a0
003a01a8  003a01a8 003a01a8 003a01b0 003a01b0
003a01b8  003a06a8 003a06a8 003a01c0 003a01c0
003a01c8  003a01c8 003a01c8 003a01d0 003a01d0
003a01d8  003a01d8 003a01d8 003a01e0 003a01e0
003a01e8  003a01e8 003a01e8 003a01f0 003a01f0

此时三个空闲块从freelist[2],freelist[4]中被摘下,合并之后链入freelist[8].

winxp 堆内存释放-快速单向链表:

快表的结构和空闲表的结构相似,表中元素为单链表表头,组织结构如下:

1
2
3
4
5
6
7
8
9
       快表
|---------------|
| lookaside[0]  |
| lookaside[1]  |-> [8bytes-> [8bytes]
| lookaside[2]  |-> [16bytes]
| ..............|..................
| lookaside[126]|
| lookaside[127]|->[1016bytes]
|---------------|

实验代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
 
#include <windows.h>
#include <windows.h>
main()
{
  HLOCAL h1,h2,h3,h4;
  HANDLE hp;
  hp = HeapCreate(0,0x0,0x0);
    getchar();
  __asm int 3;
 
    h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
    h4 = HeapAlloc(hp,HEAP_ZERO_MEMORY,24);
 
  HeapFree(hp,0,h1);free heap1 to lookaside[1];
  HeapFree(hp,0,h2);free heap2 to lookaside[1]
  HeapFree(hp,0,h3);free heap3 to lookaside[2];
  HeapFree(hp,0,h4);free heap4 to lookaside[3];
    h4 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);//alloc block from lookaside[2]
  return 0;
}

执行程序之后用windbg附加,f5,断到int3,然后单步到HeapFree(hp,0,h1)执行结束,此时观察下内存结构:

1
2
3
4
5
0:000> dd 003a0000+0x178
003a0178  003a1ee8 003a1ee8 003a0180 003a0180
003a0188  003a0188 003a0188 003a0190 003a0190
003a0198  003a0198 003a0198 003a01a0 003a01a0
003a01a8  003a01a8 003a01a8 003a01b0 003a01b0

此时我们观察下空闲块,并没有发现有是释放过的空闲块。在内存中查看下快表:

1
2
3
4
5
6
7
8
9
10
11
12
13
0:000> dd 003a0000+0x688 l50
003a0688  00000000 00000000 01000004 00000000
003a0698  00000000 00000000 00000000 00000000
003a06a8  00000000 00000004 00000000 00000000
003a06b8  00000000 00000000 01000004 00000000
003a06c8  00000000 00000000 00000000 00000000
003a06d8  00000000 00000000 00000000 00000000
003a06e8  003a1e90 00010001 01000004 00000002
003a06f8  00000002 00000001 00000000 00000000
003a0708  00000000 00000000 00000000 00000000
003a0718  00000000 00000000 01000004 00000001
003a0728  00000001 00000000 00000000 00000000
003a0738  00000000 00000000 00000000 00000000

发现在快表结构中多出了第一次我们申请到的地址0x003a1e90,在windbg中查询结果如下:

1
2
3
4
0:000> !heap -003a1e90
Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
-----------------------------------------------------------------------------
003a1e88  003a1e90  003a0000  003a0640        10      1808         8  busy

和空闲块有所不同的是,堆块的flag为busy。
单步执行完HeapFree(hp,0,h4);free heap4 to lookaside[3];之后,观察下内存中的块表信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0:000> dd 003a0000+0x688 l50
003a0688  00000000 00000000 01000004 00000000
003a0698  00000000 00000000 00000000 00000000
003a06a8  00000000 00000004 00000000 00000000
003a06b8  00000000 00000000 01000004 00000000
003a06c8  00000000 00000000 00000000 00000000
003a06d8  00000000 00000000 00000000 00000000
003a06e8  003a1ea0 00020002 01000004 00000002
003a06f8  00000002 00000002 00000000 00000000
003a0708  00000000 00000000 00000000 00000000
003a0718  003a1eb0 00010001 01000004 00000001
003a0728  00000001 00000001 00000000 00000000
003a0738  00000000 00000000 00000000 00000000
003a0748  003a1ec8 00010001 01000004 00000001
003a0758  00000001 00000001 00000000 00000000
003a0768  00000000 00000000 00000000 00000000
003a0778  00000000 00000000 01000004 00000000
 

转:win32下的堆管理系统的更多相关文章

  1. cocos2dx c++ 在mac下写的中文凝视,在win32下编译时不通过

    今天遇到个奇怪的问题,在mac下写的程序,加的中文凝视,编译没有问题,可是在win32下(使用的时vs2012, win7 64bit 系统)编译就总是报错 最后在中文凝视后 加一个空格,或者 换行, ...

  2. win32下用VC扩展PHP全过程

    闲着无聊,打算开发一些PHP组件来玩玩,由于在家没有工作环境,遂打算在win32(我的环境是vista)用VC开发DLL模块,费话不 多说了,进入正题: 一.已经在机器上安装PHP环境的就略过,否则先 ...

  3. win32下利用python操作printer

    在win32下操作printer:   1)import win32print   2) 获得默认打印机名:          >>> win32print.GetDefaultPr ...

  4. dijkstra(最短路)和Prim(最小生成树)下的堆优化

    dijkstra(最短路)和Prim(最小生成树)下的堆优化 最小堆: down(i)[向下调整]:从第k层的点i开始向下操作,第k层的点与第k+1层的点(如果有)进行值大小的判断,如果父节点的值大于 ...

  5. Win32 OpenGL 编程( 1 ) Win32 下的 OpenGL 编程必须步骤

    http://blog.csdn.net/vagrxie/article/details/4602961 Win32 OpenGL 编程( 1 ) Win32 下的 OpenGL 编程必须步骤 wri ...

  6. Win32下的中断和异常

    本文是Matt Pietrek在1997年月10月的MSJ杂志Under The Hood专栏上发表的文章.中断和异常在DOS时代是整个系统的灵魂,但Windows已将其隐藏到了系统深处.Matt P ...

  7. 【神经网络与深度学习】【CUDA开发】caffe-windows win32下的编译尝试

    [神经网络与深度学习][CUDA开发]caffe-windows win32下的编译尝试 标签:[神经网络与深度学习] [CUDA开发] 主要是在开发Qt的应用程序时,需要的是有一个使用的库文件也只是 ...

  8. [老文章搬家] [翻译] 深入解析win32 crt 调试堆

    09 年翻译的东西. 原文见:  http://www.nobugs.org/developer/win32/debug_crt_heap.html 在DeviceStudio的Debug编译模式下, ...

  9. win32下进程间通信——共享内存

    一.引言     在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换 ...

随机推荐

  1. Python数据生成pdf文件

    sklearn实战-乳腺癌细胞数据挖掘 https://study.163.com/course/introduction.htm?courseId=1005269003&utm_campai ...

  2. 全表 or 索引

    这一篇文章证实了以前对MySQL优化程序的工作原理. MySQL就像一个人一样,总是聪明的去选择当前最快的方式去查询,而不是像Oracle数据那样死板地根据规格去查询. 查询的要求在于快.而对于数据库 ...

  3. CSS文字溢出部分自动用"..."代替

    CSS文字溢出部分自动用"..."代替 如html部分: <h4><马尔代夫双鱼岛Olhuveli4 晚6 日自助游></h4> <p&g ...

  4. 写文章 使用conda管理python环境

    使用conda管理python环境

  5. Codechef Observing the Tree

    Home » Practice(Hard) » Observing the Tree   https://www.codechef.com/problems/QUERY Observing the T ...

  6. sql 流水号获取

    经常用到产生订单号等流水单号的场景,sqlserver实现流水号,如下: 表tb_b_Seq(流水号表): CREATE TABLE tb_b_Seq( Year int ,--年份 Month in ...

  7. python学习笔记(十四)之字典

    字典:是python中唯一的映射类型,字典中每一项都是由键-值对组成的项.字典中没有索引,只有键和值.键的类型可以是整型,变量或字符串. 创建和访问字典: >>> dict1 = { ...

  8. js布尔值转化

    JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值.转换规则是除了下面六个值被转为false,其他值都视为true. undefined null false 0 Na ...

  9. 一. Jmeter--使用代理录制脚本

    Jmeter脚本是以.JMX格式为主 1. Jmeter也是支持录制的,支持第三方录制方式和代理录制方式. (1).第三方录制主要是通过badboy来录制,录制后另存为jmx格式即可. (2).Jme ...

  10. 阿里分布式开源框架DUBBO 入门+ 进阶+ 项目实战视频教程

    史诗级Java/JavaWeb学习资源免费分享 欢迎关注我的微信公众号:"Java面试通关手册"(坚持原创,分享各种Java学习资源,面试题,优质文章,以及企业级Java实战项目回 ...