How can I calculate heap chunk size from raw bytes read from memory. I tried below thing.
0:001> !heap
Index Address Name Debugging options enabled
1: 00500000
2: 00280000
3: 008f0000
4: 00ab0000
5: 00cc0000
0:001> !heap -a 00500000
..
..
Heap entries for Segment00 in Heap 00500000
address: psize . size flags state (requested size)
00500000: 00000 . 00588 [101] - busy (587)
00500588: 00588 . 00240 [101] - busy (23f)
005007c8: 00240 . 00020 [101] - busy (18)
005007e8: 00020 . 00ca0 [101] - busy (c94)
..
..
!heap -a 00500000 shows that size of first chunk is 588 bytes.
If we dump the chunk header using dt _HEAP_ENTRY, it somehow shows size is 0x3822
0:001> dt _HEAP_ENTRY 00500000
ntdll!_HEAP_ENTRY
+0x000 Size : 0x3822
+0x002 Flags : 0xfc ''
+0x003 SmallTagIndex : 0xbb ''
+0x000 SubSegmentCode : 0xbbfc3822 Void
+0x004 PreviousSize : 0x1849
+0x006 SegmentOffset : 0 ''
+0x006 LFHFlags : 0 ''
+0x007 UnusedBytes : 0x1 ''
+0x000 FunctionIndex : 0x3822
+0x002 ContextValue : 0xbbfc
+0x000 InterceptorValue : 0xbbfc3822
+0x004 UnusedBytesLength : 0x1849
+0x006 EntryOffset : 0 ''
+0x007 ExtendedBlockSignature : 0x1 ''
+0x000 Code1 : 0xbbfc3822
+0x004 Code2 : 0x1849
+0x006 Code3 : 0 ''
+0x007 Code4 : 0x1 ''
+0x000 AgregateCode : 0x01001849`bbfc3822
When I dump the address 0x00500000 I find first two bytes are 22 and 38.
00500000 22 38 fc bb 49 18 00 01 ee ff ee ff 00 00 00 00 a8 00 "8..I.............
00500012 50 00 a8 00 50 00 00 00 50 00 00 00 50 00 00 01 00 00 P...P...P...P.....
00500024 88 05 50 00 00 00 60 00 cf 00 00 00 01 00 00 00 00 00 ..P...`...........
00500036 00 00 f0 0f 53 00 f0 0f 53 00 02 00 00 00 00 00 00 00 ....S...S.........
00500048 00 00 00 00 00 00 10 00 93 38 fd 0b 49 18 00 00 17 ff .........8..I.....
0050005a bb 44 00 00 00 00 00 fe 00 00 ff ee ff ee 00 00 10 00 .D................
0050006c 00 20 00 00 00 08 00 00 00 20 00 00 2e 04 00 00 ff ef . ....... ........
0050007e fd 7f 01 00 38 01 00 00 00 00 00 00 00 00 00 00 00 00 ....8.............
00500090 e8 0f 53 00 e8 0f 53 00 0f 00 00 00 f8 ff ff ff a0 00 ..S...S...........
005000a2 50 00 a0 00 50 00 10 00 50 00 10 00 50 00 00 00 00 00 P...P...P...P.....
My question is how does 22 and 38 (or 0x3822) becomes 0x588
Form Vista and later, the heap entries are scrambled so it’s a hard task to do any calculations. Check this link read about randomization.
The DT command are therefore unable do display any sensible information at all. Take a look at the offsets:
A lot of elements with same offset, hence same memory.
Also observe your
Does not correspond with the psize of 0000 from !heap –a.
On Win XP and earlier your technique was possible, but here the
was number of heap blocks, usually of 8 bytes.
Edit: I’m not aware of any manual method to decode the heap entry, but I guess it’s possible. I have used the !heap –i command to do it for me. First:
Then
Sample:
See also : this link
Summary: heap entries are now encoded, the key is in the heap itself.
Let's say I have a heap at 0x00d60000:
There's a busy block at 0x00d60480: its allocated size is 0x118 (the size of the previous block is 0x480).
If we dump this block we can see it's encoded:
Back to the heap, pay a particular attention to the field named "Encoding " (at offset 0x50):
Dumping the whole _HEAP structure:
Dumping the encoding field as two DWORDs:
Now dumping the heap entry as two DWORDs:
Let's XOR them:
Now just writing a fake _HEAP_ENTRY so we can 'dt' it:
Size field is 0x23, granularity is 8 bytes (as reported by the
!heap -a
command output). The real size of the block is theSize
field value multiplied by the granularity, so:It also works for the size of the previous block (reported to be 0x480):
We found the same sizes.
Granularity
Granularity (as given by the
!heap -a
command output) is not indicated by a specific field, it's just the size of aHEAP_ENTRY
structure:8 bytes on x86 systems (or WOW64):
16 bytes on x64 systems: