分类: WINDOWS
2014-01-28 17:57:01
原文地址:windows 堆管理调试 作者:kanghtta
之前的笔记。放出来备案。
实验环境: Win7 OEM 旗舰版 + windbg
由于windows 调试堆的支持,内部的数据管理结构有一定差异,
因此,使用附加的方式调试.这里有一个问题要注意.
在windbg,OD中,附加后可能无法调试,原因应该是int 3后进入异常处理
流程,等待debug 事件的接收,如果此时强行g或run,将无法中断在int 3
断点指令上,替代的一个办法是使用输入流函数(getchar(),cin等),但是
该方法旨在调试有source的情况下可用.
@注意: 在int 3 中断时,家里的机器和公司的表现有差异,目前尚不清楚具体
原因,公司能附加,但只有调试和关闭按钮,家里的多一个错误报告按钮,附加
后调试会话不可用.
由于默认的即时调试器是OD,这里用windbg时需要设置一下:
进入windbg 目录: windbg -I
代码使用0day 上的:
#include
main()
{
HLOCAL h1,h2,h3,h4,h5,h6;
HANDLE hp;
hp = HeapCreate(0,0x1000,0x10000);
__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);
//free block and prevent coaleses
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;
}
调试器中断后看下堆栈:
0:000> k
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ff88 766ced6c heap_debug+0x101b
0012ff94 77a7377b kernel32!BaseThreadInitThunk+0xe
0012ffd4 77a7374e ntdll!__RtlUserThreadStart+0x70
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
接下来看下hp的值:
0:000> r
eax=004f0000 ebx=7ffd8000 ecx=77a72dfa edx=77ae7500 esi=004f0000 edi=00000000
eip=0040101c esp=0012ff2c ebp=0012ff88 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
heap_debug+0x101c:
0040101c 8b3d04804000 mov edi,dword ptr [heap_debug+0x8004 (00408004)] ds:0023:00408004={ntdll!RtlAllocateHeap (77a62d66)}
由于函数返回值存放于eax中,这里看寄存器的值就可以:
也可用使用如下命令:
r eax ; or r @eax
先看下该进程的堆:
0:000> !heap
Index Address Name Debugging options enabled
1: 001d0000
2: 00010000
3: 00020000
4: 00360000
5: 004f0000
也可以从PEB结构中找到进程的堆信息:
0:000> dt nt!_PEB Heap* @$PEB
ntdll!_PEB
+0x078 HeapSegmentReserve : 0x100000
+0x07c HeapSegmentCommit : 0x2000
+0x080 HeapDeCommitTotalFreeThreshold : 0x10000
+0x084 HeapDeCommitFreeBlockThreshold : 0x1000
+0x240 HeapTracingEnabled : 0y0
0:000> dt nt!_PEB ProcessHeaps @$PEB
ntdll!_PEB
+0x090 ProcessHeaps : 0x77ae7500 -> 0x001d0000
0:000> dd 0x77ae7500 l8
77ae7500 001d0000 00010000 00020000 00360000
77ae7510 004f0000 00000000 00000000 00000000
和我们用!heap 扩展命令看到的结果是一致的.
堆块的创建:
1.HeapCreate 函数内部会依据传入的参数,在RtlCreateHeap使用PEB中的堆管理数据
初始化堆管理结构的一些字段.如保留提交大小等.
2.其次,在ntdll中RtlCreateHeap函数会调用ZwQueryVirtualMemory或
ZwAllocateVirtualMemory 从虚拟内存管理器得到一个内存块,
这个内存块的地址就是HeapCreate 成功后返回的堆块地址.
3.在2成功后,RtlCreateHeap内部会初始化HEAP结构体的各个成员.包括
FreeList的初始化.
4.这之后的堆分配或堆释放都基于HEAP堆管理的数据结构.
首先看一下HEAP开头的数据结构有哪些:
0:000> dt ntdll!_HEAP_*
ntdll!_HEAP_LIST_LOOKUP
ntdll!_HEAP_ENTRY
ntdll!_HEAP_TAG_ENTRY
ntdll!_HEAP_PSEUDO_TAG_ENTRY
ntdll!_HEAP_LOCK
ntdll!_HEAP_COUNTERS
ntdll!_HEAP_TUNING_PARAMETERS
ntdll!_HEAP_SEGMENT
ntdll!_HEAP_FREE_ENTRY
ntdll!_HEAP_FAILURE_TYPE
ntdll!_HEAP_SUBSEGMENT
ntdll!_HEAP_LOCAL_SEGMENT_INFO
ntdll!_HEAP_USERDATA_HEADER
ntdll!_HEAP_USERDATA_HEADER
ntdll!_HEAP_BUCKET_COUNTERS
ntdll!_HEAP_LOCAL_DATA
ntdll!_HEAP_LOCAL_DATA
ntdll!_HEAP_BUCKET_RUN_INFO
ntdll!_HEAP_BUCKET
ntdll!_HEAP_BUCKET
ntdll!_HEAP_FAILURE_INFORMATION
ntdll!_HEAP_UCR_DESCRIPTOR
ntdll!_HEAP_ENTRY_EXTRA
ntdll!_HEAP_DEBUGGING_INFORMATION
下面,我们来看一下堆管理的几个重要的数据结构.
HEAP 堆管理器用HEAP结构来记录和维护堆的管理信息.
HEAP_SEGMENT 堆段和HEAP部分字段重叠,一个堆可能有多个堆段.
在win7种原来的segments 结构由数组变为链表.
HEAP_ENTRY 堆块,程序中真正能使用的部分.
HEAP_ENTRY_FREE 以及其它堆管理数据结构,但这里重要介绍上面几种.
我们看一下HeapCreate 创建的堆块最开始是什么样?
0:000> dt _HEAP 004f0000
ntdll!_HEAP
+0x000 Entry : _HEAP_ENTRY 用于存放堆管理数据结构的堆块结构
+0x008 SegmentSignature : 0xffeeffee 堆段结构签名
+0x00c SegmentFlags : 0 堆段标志
+0x010 SegmentListEntry : _LIST_ENTRY [ 0x4f00a8 - 0x4f00a8 ] 堆段链表,这里是和win2003 ,nt 有区别的地方
+0x018 Heap : 0x004f0000 _HEAP
+0x01c BaseAddress : 0x004f0000
+0x020 NumberOfPages : 0x10 堆块占用的内存页数
+0x024 FirstEntry : 0x004f0588 _HEAP_ENTRY 第一个堆块
+0x028 LastValidEntry : 0x00500000 _HEAP_ENTRY
+0x02c NumberOfUnCommittedPages : 0xf 尚未提交的内存页数
+0x030 NumberOfUnCommittedRanges : 1 UnCommittedRanges 数组元素数
+0x034 SegmentAllocatorBackTraceIndex : 0 初始化段的UST 记录序号
+0x036 Reserved : 0
+0x038 UCRSegmentList : _LIST_ENTRY [ 0x4f0ff0 - 0x4f0ff0 ]
+0x040 Flags : 0x1000 堆的标志,标示该堆段的属性,是否可增长,是否启用堆检查。
+0x044 ForceFlags : 0 强制标志,和堆释放有关
+0x048 CompatibilityFlags : 0
+0x04c EncodeFlagMask : 0x100000 是否启用编码功能
+0x050 Encoding : _HEAP_ENTRY 编码后的HEAP_ENTRY结构,这个很重要,win7的一个变化也在此,后面会讲下。
+0x058 PointerKey : 0x77c065cf
+0x05c Interceptor : 0
+0x060 VirtualMemoryThreshold : 0xfe00 以分配粒度为单位的堆块阀值 (508K )
+0x064 Signature : 0xeeffeeff
+0x068 SegmentReserve : 0x100000 堆段保留大小
+0x06c SegmentCommit : 0x2000 堆段提交大小
+0x070 DeCommitFreeBlockThreshold : 0x200 和释放堆内存有关,本次释放堆块阀值
+0x074 DeCommitTotalFreeThreshold : 0x2000 堆释放有关,总空闲空间阀值
+0x078 TotalFreeSize : 0x14b 堆块空闲空间
+0x07c MaximumAllocationSize : 0x7ffdefff
+0x080 ProcessHeapsListIndex : 5 PEB中ProcessHaaps的索引
+0x082 HeaderValidateLength : 0x138
+0x084 HeaderValidateCopy : (null)
+0x088 NextAvailableTagIndex : 0
+0x08a MaximumTagIndex : 0
+0x08c TagEntries : (null)
+0x090 UCRList : _LIST_ENTRY [ 0x4f0fe8 - 0x4f0fe8 ]
+0x098 AlignRound : 0xf
+0x09c AlignMask : 0xfffffff8 用于地址对齐的掩码
+0x0a0 VirtualAllocdBlocks : _LIST_ENTRY [ 0x4f00a0 - 0x4f00a0 ] 虚拟内存分配块链表,超过堆块阀值将在此分配
+0x0a8 SegmentList : _LIST_ENTRY [ 0x4f0010 - 0x4f0010 ] 堆段链表,win2003 为数组。
+0x0b0 AllocatorBackTraceIndex : 0
+0x0b4 NonDedicatedListLength : 0
+0x0b8 BlocksIndex : 0x004f0150
+0x0bc UCRIndex : (null)
+0x0c0 PseudoTagEntries : (null)
+0x0c4 FreeLists : _LIST_ENTRY [ 0x4f0590 - 0x4f0590 ] 空闲堆块链表,堆分配用 (后端堆)
+0x0cc LockVariable : 0x004f0138 _HEAP_LOCK 控制线程系列化
+0x0d0 CommitRoutine : 0x77c065cf long +77c065cf
+0x0d4 FrontEndHeap : (null) 用于快速释放堆块的前端堆
+0x0d8 FrontHeapLockCount : 0 前端堆锁定计数
+0x0da FrontEndHeapType : 0 ''
+0x0dc Counters : _HEAP_COUNTERS
+0x130 TuningParameters : _HEAP_TUNING_PARAMETERS
堆段数据结构,参考HEAP前面的说明:
0:000> dt _HEAP_SEGMENT 004f0000
ntdll!_HEAP_SEGMENT
+0x000 Entry : _HEAP_ENTRY
+0x008 SegmentSignature : 0xffeeffee
+0x00c SegmentFlags : 0
+0x010 SegmentListEntry : _LIST_ENTRY [ 0x4f00a8 - 0x4f00a8 ]
+0x018 Heap : 0x004f0000 _HEAP
+0x01c BaseAddress : 0x004f0000
+0x020 NumberOfPages : 0x10
+0x024 FirstEntry : 0x004f0588 _HEAP_ENTRY
+0x028 LastValidEntry : 0x00500000 _HEAP_ENTRY
+0x02c NumberOfUnCommittedPages : 0xf
+0x030 NumberOfUnCommittedRanges : 1
+0x034 SegmentAllocatorBackTraceIndex : 0
+0x036 Reserved : 0
+0x038 UCRSegmentList : _LIST_ENTRY [ 0x4f0ff0 - 0x4f0ff0 ]
我们来看一下刚分配的堆结构信息:
0:000> !heap -a 004f0000
Index Address Name Debugging options enabled
5: 004f0000
Segment at 004f0000 to 00500000 (00001000 bytes committed)
Flags: 00001000
ForceFlags: 00000000
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 0000014b
Max. Allocation Size: 7ffdefff
Lock Variable at: 004f0138
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 004f00a0
Uncommitted ranges: 004f0090
004f1000: 0000f000 (61440 bytes)
FreeList[ 00 ] at 004f00c4: 004f0590 . 004f0590
004f0588: 00588 . 00a58 [100] - free
Segment00 at 004f0000:
Flags: 00000000
Base: 004f0000
First Entry: 004f0588
Last Entry: 00500000
Total Pages: 00000010
Total UnCommit: 0000000f
Largest UnCommit:00000000
UnCommitted Ranges: (1)
Heap entries for Segment00 in Heap 004f0000
004f0000: 00000 . 00588 [101] - busy (587)
004f0588: 00588 . 00a58 [100]
004f0fe0: 00a58 . 00020 [111] - busy (1d)
004f1000: 0000f000 - uncommitted bytes.
windows堆管理器,将从虚拟内存管理器中申请来的内存划分为一系列的堆块。
每个堆块的起始处都是8字节的HEAP_ENTRY结构,随后是该堆块的用户区,
而HEAP结构中包含了最大的堆块长度,如果申请的堆大小超过该阀值,并且
该堆为可增长的,那么,堆管理器将直接向虚拟内存管理器申请。故此一个
堆也可以看作堆块的链表.
我们看第一个HEAP_ENTRY :
0:000> dt _HEAP_ENTRY 004f0000
ntdll!_HEAP_ENTRY
+0x000 Size : 0x93b8 堆块的大小,已分配粒度为单位
+0x002 Flags : 0x1e '' 堆块状态标志
+0x003 SmallTagIndex : 0xf3 '' 用于检查堆溢出的cookie
+0x000 SubSegmentCode : 0xf31e93b8
+0x004 PreviousSize : 0xbfa 前一堆块大小
+0x006 SegmentOffset : 0 ''
+0x006 LFHFlags : 0 '' 低碎片堆标志
+0x007 UnusedBytes : 0x1 '' 对齐用,
+0x000 FunctionIndex : 0x93b8
+0x002 ContextValue : 0xf31e
+0x000 InterceptorValue : 0xf31e93b8
+0x004 UnusedBytesLength : 0xbfa
+0x006 EntryOffset : 0 '' 堆块偏移
+0x007 ExtendedBlockSignature : 0x1 ''
+0x000 Code1 : 0xf31e93b8
+0x004 Code2 : 0xbfa
+0x006 Code3 : 0 ''
+0x007 Code4 : 0x1 ''
+0x000 AgregateCode : 0x1000bfa`f31e93b8
Flags:
|------------------------------------------------------------------------
| 标志 | 值 | 含义 |
|------------------------------------------------------------------------
|HEAP_ENTRY_BUSY | 01 | 堆块处于占用状态 |
|------------------------------------------------------------------------
|HEAP_ENTRY_EXTRY_PRESENT | 02 | 存在额外描述 |
|------------------------------------------------------------------------
|HEAP_ENTRY_FILL_PATTERN | 03 | 使用固定模式填充堆块|
|------------------------------------------------------------------------
|HEAP_ENTRY_VIRTUAL_ALLOC | 04 | 虚拟分配 |
|------------------------------------------------------------------------
|HEAP_ENTRY_LAST_ENTRY | 0x10 | 这是最后一个块 |
|------------------------------------------------------------------------
我们上面通过!haap堆扩展显示的第一个堆块大小为00588这里是0x93b8 ,why?
这要回到我们HEAP中Encoding,当启用了编码功能,其实就是将一个堆块和编码
的堆块模板作异或操作,我们要还原真实的大小,得先找到Encoding 对应的HEAP_ENTRY结构
0:000> dt _HEAP Encoding 004f0000
ntdll!_HEAP
+0x050 Encoding : _HEAP_ENTRY
0:000> dt _HEAP Encoding. 004f0000
ntdll!_HEAP
+0x050 Encoding :
+0x000 Size : 0x9309
+0x002 Flags : 0x1f ''
+0x003 SmallTagIndex : 0x43 'C'
+0x000 SubSegmentCode : 0x431f9309
+0x004 PreviousSize : 0xbfa
+0x006 SegmentOffset : 0 ''
+0x006 LFHFlags : 0 ''
+0x007 UnusedBytes : 0 ''
+0x000 FunctionIndex : 0x9309
+0x002 ContextValue : 0x431f
+0x000 InterceptorValue : 0x431f9309
+0x004 UnusedBytesLength : 0xbfa
+0x006 EntryOffset : 0 ''
+0x007 ExtendedBlockSignature : 0 ''
+0x000 Code1 : 0x431f9309
+0x004 Code2 : 0xbfa
+0x006 Code3 : 0 ''
+0x007 Code4 : 0 ''
+0x000 AgregateCode : 0xbfa`431f9309
我们将对应的字段异或:
0:000> ?(9309^93b8)
Evaluate expression: 177 = 000000b1
0:000> ?b1*8
Evaluate expression: 1416 = 00000588
0:000> ?(0x1f ^ 0x1e)
Evaluate expression: 1 = 00000001
可以看出,大小和之前的一致.
我们在一路pc 到释放第一个堆块处:
0:000> dt _HEAP FreeLists. 004f0000
ntdll!_HEAP
+0x0c4 FreeLists : [ 0x4f0590 - 0x4f0610 ]
+0x000 Flink : 0x004f0590 _LIST_ENTRY [ 0x4f0610 - 0x4f00c4 ]
+0x004 Blink : 0x004f0610 _LIST_ENTRY [ 0x4f00c4 - 0x4f0590 ]
0:000> pc ;p ;!heap -a 004f0000 ;
Index Address Name Debugging options enabled
5: 004f0000
Segment at 004f0000 to 00500000 (00001000 bytes committed)
Flags: 00001000
ForceFlags: 00000000
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 0000013d
Max. Allocation Size: 7ffdefff
Lock Variable at: 004f0138
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 004f00a0
Uncommitted ranges: 004f0090
004f1000: 0000f000 (61440 bytes)
FreeList[ 00 ] at 004f00c4: 004f0610 . 004f0590
004f0588: 00588 . 00010 [100] - free
004f0608: 00020 . 009d8 [100] - free
Segment00 at 004f0000:
Flags: 00000000
Base: 004f0000
First Entry: 004f0588
Last Entry: 00500000
Total Pages: 00000010
Total UnCommit: 0000000f
Largest UnCommit:00000000
UnCommitted Ranges: (1)
Heap entries for Segment00 in Heap 004f0000
004f0000: 00000 . 00588 [101] - busy (587)
004f0588: 00588 . 00010 [100] ;free
004f0598: 00010 . 00010 [101] - busy (5)
004f05a8: 00010 . 00010 [101] - busy (6)
004f05b8: 00010 . 00010 [101] - busy (8)
004f05c8: 00010 . 00020 [101] - busy (13)
004f05e8: 00020 . 00020 [101] - busy (18)
004f0608: 00020 . 009d8 [100] ;free
004f0fe0: 009d8 . 00020 [111] - busy (1d)
004f1000: 0000f000 - uncommitted bytes.
0:000> !list "-t _LIST_ENTRY.Flink -e -x \"dd @$extret l2 ;dt _LIST_ENTRY @$extret\" 004f00c4"
dd @$extret l2 ;dt _LIST_ENTRY @$extret
004f00c4 004f0590 004f0610
ntdll!_LIST_ENTRY
[ 0x4f0590 - 0x4f0610 ]
+0x000 Flink : 0x004f0590 _LIST_ENTRY [ 0x4f0610 - 0x4f00c4 ]
+0x004 Blink : 0x004f0610 _LIST_ENTRY [ 0x4f00c4 - 0x4f0590 ]
dd @$extret l2 ;dt _LIST_ENTRY @$extret
004f0590 004f0610 004f00c4
ntdll!_LIST_ENTRY
[ 0x4f0610 - 0x4f00c4 ]
+0x000 Flink : 0x004f0610 _LIST_ENTRY [ 0x4f00c4 - 0x4f0590 ]
+0x004 Blink : 0x004f00c4 _LIST_ENTRY [ 0x4f0590 - 0x4f0610 ]
0:000> !list "-t _LIST_ENTRY.Flink -e -x \"dd @$extret l2 ;dt _LIST_ENTRY @$extret\" 004f0590"
dd @$extret l2 ;dt _LIST_ENTRY @$extret
004f0590 004f0610 004f00c4
ntdll!_LIST_ENTRY
[ 0x4f0610 - 0x4f00c4 ]
+0x000 Flink : 0x004f0610 _LIST_ENTRY [ 0x4f00c4 - 0x4f0590 ]
+0x004 Blink : 0x004f00c4 _LIST_ENTRY [ 0x4f0590 - 0x4f0610 ]
dd @$extret l2 ;dt _LIST_ENTRY @$extret
004f0610 004f00c4 004f0590
ntdll!_LIST_ENTRY
[ 0x4f00c4 - 0x4f0590 ]
+0x000 Flink : 0x004f00c4 _LIST_ENTRY [ 0x4f0590 - 0x4f0610 ]
+0x004 Blink : 0x004f0590 _LIST_ENTRY [ 0x4f0610 - 0x4f00c4 ]
接下来我们释放大小为6的结点:
0:000> pc ;p ;!heap -a 004f0000 ;
Index Address Name Debugging options enabled
5: 004f0000
Segment at 004f0000 to 00500000 (00001000 bytes committed)
Flags: 00001000
ForceFlags: 00000000
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 0000013f
Max. Allocation Size: 7ffdefff
Lock Variable at: 004f0138
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 004f00a0
Uncommitted ranges: 004f0090
004f1000: 0000f000 (61440 bytes)
FreeList[ 00 ] at 004f00c4: 004f0610 . 004f05b0
004f05a8: 00010 . 00010 [100] - free
004f0588: 00588 . 00010 [100] - free
004f0608: 00020 . 009d8 [100] - free
Segment00 at 004f0000:
Flags: 00000000
Base: 004f0000
First Entry: 004f0588
Last Entry: 00500000
Total Pages: 00000010
Total UnCommit: 0000000f
Largest UnCommit:00000000
UnCommitted Ranges: (1)
Heap entries for Segment00 in Heap 004f0000
004f0000: 00000 . 00588 [101] - busy (587)
004f0588: 00588 . 00010 [100]
004f0598: 00010 . 00010 [101] - busy (5)
004f05a8: 00010 . 00010 [100]
004f05b8: 00010 . 00010 [101] - busy (8)
004f05c8: 00010 . 00020 [101] - busy (13)
004f05e8: 00020 . 00020 [101] - busy (18)
004f0608: 00020 . 009d8 [100]
004f0fe0: 009d8 . 00020 [111] - busy (1d)
004f1000: 0000f000 - uncommitted bytes.
0:000> !list "-t _LIST_ENTRY.Flink -e -x \"dd @$extret l2 ;dt _LIST_ENTRY @$extret\" 004f00c4"
dd @$extret l2 ;dt _LIST_ENTRY @$extret
004f00c4 004f05b0 004f0610
ntdll!_LIST_ENTRY
[ 0x4f05b0 - 0x4f0610 ]
+0x000 Flink : 0x004f05b0 _LIST_ENTRY [ 0x4f0590 - 0x4f00c4 ]
+0x004 Blink : 0x004f0610 _LIST_ENTRY [ 0x4f00c4 - 0x4f0590 ]
dd @$extret l2 ;dt _LIST_ENTRY @$extret
004f05b0 004f0590 004f00c4
ntdll!_LIST_ENTRY
[ 0x4f0590 - 0x4f00c4 ]
+0x000 Flink : 0x004f0590 _LIST_ENTRY [ 0x4f0610 - 0x4f05b0 ]
+0x004 Blink : 0x004f00c4 _LIST_ENTRY [ 0x4f05b0 - 0x4f0610 ]
dd @$extret l2 ;dt _LIST_ENTRY @$extret
004f0590 004f0610 004f05b0
ntdll!_LIST_ENTRY
[ 0x4f0610 - 0x4f05b0 ]
+0x000 Flink : 0x004f0610 _LIST_ENTRY [ 0x4f00c4 - 0x4f0590 ]
+0x004 Blink : 0x004f05b0 _LIST_ENTRY [ 0x4f0590 - 0x4f00c4 ]
ntdll!RtlAllocateHeap:
77a62d66 8bff mov edi,edi
77a62d68 55 push ebp
77a62d69 8bec mov ebp,esp
77a62d6b 83ec60 sub esp,60h
77a62d6e 53 push ebx
77a62d6f 56 push esi
77a62d70 33f6 xor esi,esi
77a62d72 817d10ffffff7f cmp dword ptr [ebp+10h],7FFFFFFFh ;比较分配的大小
77a62d79 57 push edi
77a62d7a 8975f8 mov dword ptr [ebp-8],esi
77a62d7d 0f87eeae0200 ja ntdll!RtlAllocateHeap+0x79 (77a8dc71)
77a62d83 8b5d08 mov ebx,dword ptr [ebp+8] ;ebx = heapHandle
77a62d86 8b4344 mov eax,dword ptr [ebx+44h] ds:0023:004f0044=00000000 ; HEAP.ForceFlags
77a62d89 8b4b5c mov ecx,dword ptr [ebx+5Ch] ;HEAP.Interceptor
77a62d8c 09450c or dword ptr [ebp+0Ch],eax ;Flag or HEAP.ForceFlags
77a62d8f 894df4 mov dword ptr [ebp-0Ch],ecx ; [ebp-0ch ] is ntdll!_HEAP.Interceptor
77a62d92 3bce cmp ecx,esi ; 判断 Interceptor 是否为0
77a62d94 0f858eae0200 jne ntdll!RtlAllocateHeap+0x30 (77a8dc28) ;不为0则跳转
77a62d9a f7450c610f817d test dword ptr [ebp+0Ch],7D810F61h ;Flags & 7D810f61h
77a62da1 0f85b12c0000 jne ntdll!RtlAllocateHeap+0x222 (77a65a58)
77a62da7 397510 cmp dword ptr [ebp+10h],esi ;Size 是否为0.
77a62daa 0f8429210100 je ntdll!RtlAllocateHeap+0x19a (77a74ed9)
77a62db0 8b4510 mov eax,dword ptr [ebp+10h]
77a62db3 83c00f add eax,0Fh
77a62db6 83e0f8 and eax,0FFFFFFF8h ;分配粒度计算
77a62db9 8bc8 mov ecx,eax
77a62dbb 8945f8 mov dword ptr [ebp-8],eax ;存储实际分配大小 AllocationSize
77a62dbe 8b83b8000000 mov eax,dword ptr [ebx+0B8h] ;ntdll!_HEAP.BlocksIndex 这里为0
_Heap.BlocksIndex
004f0150 00000000 00000080 00000001 00000001
004f0160 00000001 00000000 004f00c4 004f0174
004f0170 004f0184 00000000 00000000 00000000
004f0180 80000000 00000000 00000000 00000000
004f0190 00000000 00000000 00000000 00000000
004f01a0 00000000 00000000 00000000 00000000
004f01b0 00000000 00000000 00000000 00000000
004f01c0 00000000 00000000 00000000 00000000
77a62dc4 c1e903 shr ecx,3 ;AllocationIndex = AllocationSize >> HEAP_GRANULARITY_SHIFT;
77a62dc7 3b4804 cmp ecx,dword ptr [eax+4] ;[eax+4] HEAP_MAXIMUM_FREELISTS AllocationIndex < 128
77a62dca 0f834f3a0000 jae ntdll!RtlAllocateHeap+0x1b3 (77a6681f)
77a62dd0 8b5004 mov edx,dword ptr [eax+4] ;HEAP_MAXIMUM_FREELISTS to edx
77a62dd3 4a dec edx
77a62dd4 3bca cmp ecx,edx ;if (AllocationIndex < edx-1)
77a62dd6 0f8323750000 jae ntdll!RtlAllocateHeap+0x1ce (77a6a2ff)
77a62ddc 2b4814 sub ecx,dword ptr [eax+14h]
77a62ddf 83780800 cmp dword ptr [eax+8],0 ;判断[eax+8] 是否为0
77a62de3 7402 je ntdll!RtlAllocateHeap+0x1e3 (77a62de7)
77a62de5 03c9 add ecx,ecx ;AllocationIndex *2
77a62de7 8b4020 mov eax,dword ptr [eax+20h]
77a62dea 8d3488 lea esi,[eax+ecx*4]
77a62ded 85f6 test esi,esi ;测试是否相等
77a62def 0f84632c0000 je ntdll!RtlAllocateHeap+0x222 (77a65a58)
77a62df5 8b4604 mov eax,dword ptr [esi+4]
77a62df8 a801 test al,1
77a62dfa 0f84582c0000 je ntdll!RtlAllocateHeap+0x222 (77a65a58)
77a62e00 8b5510 mov edx,dword ptr [ebp+10h]
77a62e03 8d48ff lea ecx,[eax-1]
77a62e06 c745f002000000 mov dword ptr [ebp-10h],2
77a62e0d e842000000 call ntdll!RtlpLowFragHeapAllocFromContext (77a62e54)
77a62e12 8bf8 mov edi,eax
77a62e14 85ff test edi,edi
77a62e16 0f843c2c0000 je ntdll!RtlAllocateHeap+0x222 (77a65a58)
77a62e1c f6450c08 test byte ptr [ebp+0Ch],8
77a62e20 0f85d2bc0000 jne ntdll!RtlAllocateHeap+0x212 (77a6eaf8)
77a62e26 85ff test edi,edi
77a62e28 0f8445ae0200 je ntdll!RtlAllocateHeap+0x7b (77a8dc73)
77a62e2e 8b75f4 mov esi,dword ptr [ebp-0Ch]
77a62e31 85f6 test esi,esi
77a62e33 0f854eaf0200 jne ntdll!RtlAllocateHeap+0x24f (77a8dd87)
77a62e39 803d8003fe7f00 cmp byte ptr [SharedUserData+0x380 (7ffe0380)],0
77a62e40 0f858bae0200 jne ntdll!RtlAllocateHeap+0xe1 (77a8dcd1)
77a62e46 8bc7 mov eax,edi
77a62e48 5f pop edi
77a62e49 5e pop esi
77a62e4a 5b pop ebx
77a62e4b c9 leave
77a62e4c c20c00 ret 0Ch
后端堆:
77a65a58 8b550c mov edx,dword ptr [ebp+0Ch] ss:0023:0012ff24=00000008 ;Size
77a65a5b 8d45f0 lea eax,[ebp-10h]
77a65a5e 50 push eax
77a65a5f 56 push esi ; ref: 77a62dea lea esi,[eax+ecx*4]
77a65a60 ff75f8 push dword ptr [ebp-8] ; AllocateSize
77a65a63 83ca02 or edx,2
77a65a66 ff7510 push dword ptr [ebp+10h] ;Size
77a65a69 8bcb mov ecx,ebx ;ebx is heapHandle: _HEAP
77a65a6b e80c000000 call ntdll!RtlpAllocateHeap (77a65a7c)
77a65a70 8bf8 mov edi,eax
77a65a72 e9afd3ffff jmp ntdll!RtlAllocateHeap+0x23c (77a62e26)