SDK版本:10.0.18362.0
msvc在debug模式中会在程序申请堆内存时作出一定处理,为了探究内存结构,写出如下调试程序:
void *p[20];
for (int i=0;i<20;i++) {
p[i] = malloc(0x1000);
}
以下为对内存的分析,截取了两块堆内存中间的区域作为例子。
0x0000022B2D5C32C0 cd cd cd cd cd cd cd cd ???????? // 数据区
0x0000022B2D5C32C8 cd cd cd cd cd cd cd cd ???????? // 数据区
0x0000022B2D5C32D0 fd fd fd fd 00 00 00 00 ????.... // unsigned char _another_gap[no_mans_land_size] + pad
0x0000022B2D5C32D8 dc 60 39 b0 c0 95 00 0c ?`9???.. // ?
以下为新的malloc(Heapmalloc)分配的块,大小0x1038,其中cookie为56B
0x0000022B2D5C32E0 a0 22 5c 2d 2b 02 00 00 ?"\-+... // _CrtMemBlockHeader* _block_header_next
0x0000022B2D5C32E8 20 43 5c 2d 2b 02 00 00 C\-+... // _CrtMemBlockHeader* _block_header_prev
0x0000022B2D5C32F0 00 00 00 00 00 00 00 00 ........ // char const* _file_name
0x0000022B2D5C32F8 00 00 00 00 01 00 00 00 ........ // int _line_number + int _block_use
0x0000022B2D5C3300 00 10 00 00 00 00 00 00 ........ // size_t _data_size
0x0000022B2D5C3308 a5 00 00 00 fd fd fd fd ?...???? // long _request_number + unsigned char _gap[no_mans_land_size]
0x0000022B2D5C3310 cd cd cd cd cd cd cd cd ???????? // 数据区
0x0000022B2D5C3318 cd cd cd cd cd cd cd cd ???????? // 数据区
调试模式下,malloc转而调用_malloc_dbg
in malloc.cpp, line 23
return _malloc_dbg(size, _NORMAL_BLOCK, nullptr, 0);
1 0 0
调整大小以容纳调试头
in debug_heap.cpp, line 357
size_t const block_size{sizeof(_CrtMemBlockHeader) + size + no_mans_land_size};
0x1034 0x30 0x100 0x4
in line 65: static size_t const no_mans_land_size = 4;
in line 83:
// For diagnostic purpose, blocks are allocated in the debug heap with extra
// information and stored in a doubly-linked list. This makes all blocks
// registered with how big they are, when they were allocated, and what they are
// used for.
struct _CrtMemBlockHeader
{
_CrtMemBlockHeader* _block_header_next;
_CrtMemBlockHeader* _block_header_prev;
char const* _file_name;
int _line_number;
int _block_use;
size_t _data_size;
long _request_number;
unsigned char _gap[no_mans_land_size];
// Followed by:
// unsigned char _data[_data_size];
// unsigned char _another_gap[no_mans_land_size];
};
注意:in vcruntime.h, line 193: typedef unsigned __int64 size_t;
调用win32 api HeapAlloc 完成内存获取
in debug_heap.cpp, line 359:
_CrtMemBlockHeader* const header{static_cast<_CrtMemBlockHeader*>(HeapAlloc(__acrt_heap, 0, block_size))};
最后写入调试头,将gap填充为no_mans_land_fill(0xfd),将数据区填充为clean_land_fill(0xcd),完成malloc过程。
调用栈:
ucrtbased.dll!malloc(unsigned __int64 size=4096) 行 27
ucrtbased.dll!_malloc_dbg(unsigned __int64 size=4096, int block_use=1, const char * file_name=0x0000000000000000, int line_number=0) 行 496
ucrtbased.dll!heap_alloc_dbg(const unsigned __int64 size=4096, const int block_use=1, const char * const file_name=0x0000000000000000, const int line_number=0) 行 450
ucrtbased.dll!heap_alloc_dbg_internal(const unsigned __int64 size=4096, const int block_use=1, const char * const file_name=0x0000000000000000, const int line_number=0) 行 357
ntdll.dll!RtlAllocateHeap() 注:Win32 Api
ntdll.dll!RtlpAllocateHeap()
ntdll.dll!RtlpExtendHeap()
ntdll.dll!RtlpFindAndCommitPages()
ntdll.dll!RtlpFindUCREntry()
ntdll.dll!RtlpGetHeapProtection()
ntdll.dll!RtlpHpHeapValidateProtection()
ntdll.dll!RtlpHpHeapCheckCommitLimit()
ntdll.dll!NtAllocateVirtualMemory()
a syscall
ntdll.dll!RtlGetCurrentServiceSessionId()
ntdll.dll!RtlpRemoveUCRBlock()
ntdll.dll!RtlpUpdateUCRIndexRemove()
ntdll.dll!RtlpCreateUCREntry()
ntdll.dll!RtlpInsertUCRBlock()
ntdll.dll!RtlpFindUCREntry()
ntdll.dll!RtlpUpdateUCRIndexInsert()
ntdll.dll!RtlGetCurrentServiceSessionId()
ntdll.dll!RtlGetCurrentServiceSessionId()
ntdll.dll!RtlpCoalesceFreeBlocks()
ntdll.dll!RtlpHeapRemoveListEntry()
ntdll.dll!RtlpInsertFreeBlock()
ntdll.dll!RtlpFindEntry()
ntdll.dll!RtlpHeapFindListLookupEntry()
ntdll.dll!RtlpHeapAddListEntry()
ntdll.dll!RtlpHeapRemoveListEntry()
ntdll.dll!RtlpInsertFreeBlock()
ntdll.dll!RtlpFindEntry()
ntdll.dll!RtlpHeapAddListEntry()
ntdll.dll!RtlpHeapRemoveListEntry()
ntdll.dll!RtlLeaveCriticalSection()
3*memset()