Windows Heap Note
0x0 Enviroment:
- Windows 7 SP1 32-bit
- Windbg
0x1 A simple code:
0x2 HEAP Alloc
The code creates a heap with 0x1000 at first and can be 0x10000. Load the relase version into windbg
Check heap status: !heap -stat
Address 00880000 points to the heap that we created. Other one is process default heap.
we can see that Reserved bytes size is 0x10000 and Committed bytes 0x1000, which specified in hp = HeapCreate(0, 0x1000, 0x10000);
.
Then !heap -a 00880000
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
|
In the result, there is a FreeList which is a linked list data structure. It stores addresses of free blocks. Right now it is in address 008800c4. Since there is no malloc operation yet, this freelist only point to a free block at 0x00880590.
The last part of the result shows heap information:
We can see that the memeory we committed is divied into 3 parts. 0x00880588 is the free block (0x00880590) pointed by freelist. The first 8 bytes stores heap header information.
Freelist table will point to the address (0x00880590) after heap header (0x00880588). When the block is free, there are 8 bytes right after heap header infomation which stores pre and next pointers (here both are 0x008800c4).
Next we want to analze the heap malloc and free process. Open the exe using IDA Pro
The base is 0x400000.
and we want to set breakpoint at the first heapalloc function, which is 0x00401026.
Check application’s start address in windbg:
lmf m ConsoleApplication1
so the address we can set breakpoint is :
set the breakppoint and run.
before first allocation:
After first allocation:
As we can see before allocation. address 0x00880588 is one whole heap. After the allocation, it gives 0x10 heap, which contains 8 byte heap header information, 3 bytes user data and 5 bytes fills.
Lets check 0x00880588 heap header.
dt _HEAP_ENTRY 00880588
Clearly, the value is wrong. The reason is when the heapalloc funciton returns, that heap header values is done with xor operation.
Let’s find out
dt _HEAP 00880000
Encoding value is in offset 0x50
dd 0x00880000 + 0x50
found the encoding value is 0x64717779
Revisit the first 4 bytes of heap entry value:
it is 0x6770777b
? 64717779^6770777b
got value is 0x03010002.
0x0002 means this heap is 2 blocks; 0x01 means this heap is busy; 0x03 means SmallTagIndex; Notice: 32 bits system one block is 8 bytes, while 64 bits system one block is 16 bytes.
0x3 HEAP Free
After h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 6); check heap !heap -a 0x00880000
FreeList at 008800c4 and points to block 008805c0. and this block’s pre and next pointers point to FreeList .
Notice, these pointers are stored after 8 bytes heap header information.
After a few heap free operations.
Freelist has 3 blocks:
These blocks are in order. When new heap alloc request comes in, function will go throught this free list and find the same size block, or find one to split it.
For example, code requests 0xc size, it will get 0x18 (0x08 + 0x0c) block.
When heap free the block, it may combine with its neighbor. In this case, we fre h1, h3, h5. since their neighbors are in busy status, they will not combine to one block.
But after h2 is freed, block will combine:
Note:
When debugging a heap code, you need to run the program first and then attach the windbg.