2. Windows Heap Exploitation
• Windows Memory Allocator
• NT heap
• BackEnd
• Exploitation
• FrontEnd
• LowFragmentationHeap
• Exploitation
3. Windows memory allocator
• Memory allocator in Win10 is very complicated, there are mainly two kind
of memory allocator.
• Nt Heap
• Default memory allocator
• SegmentHeap
• New memory allocator in Win10
• Some system process and UWP will use.
4. Windows memory allocator
• Nt Heap can be divided into
• Back-End
• Front-End
• LowFragmentationHeap
• In order to prevent memory fragmentation problem, it will enable LFH
after allocating a certain number of the same size of chunk. (e.g.
Continuously allocate same size of chunks 18 times)
• Size <= 0x4000
5. Windows memory allocator
• The slide based on win10 (1809)
• OS build - 17763.379
• Later versions may not be completely correct
• 1903 is very smimilar
• The structure of heap often change a lot. In the new release version,
you need to trace the structure and workflow by yourself.
7. Windows memory allocator
• When we call malloc if LFH is disable.
Kernel32.dll
HeapAlloc
HeapFree
msvcrt140.dll
malloc
free
ntdll.dll
RtlAllocateHeap
RtlFreeHeap
ntdll.dll
RtlpAllocateHeap
RtlpFreeHeap
Kernel
Back-End
8. Windows memory allocator
• When we call malloc at the first time or when
memory pool called userblock of LFH is used
up if LFH is enable.
• It will use back-end allocator to allocate
userblock for LFH.
Kernel32.dll
HeapAlloc
HeapFree
msvcrt140.dll
malloc
free
ntdll.dll
RtlAllocateHeap
RtlFreeHeap
ntdll.dll
RtlpAllocateHeap
RtlpFreeHeap
ntdll.dll
RtlpLowFragHeapAlloc
RtlpLowFragHeapFree
Kernel
Front-End
Back-End
9. Windows memory allocator
• When we allocate the same size after enabling LFH,
it will use front-end allocator and use userblock in
LFH
Kernel32.dll
HeapAlloc
HeapFree
msvcrt140.dll
malloc
free
ntdll.dll
RtlAllocateHeap
RtlFreeHeap
ntdll.dll
RtlpLowFragHeapAlloc
RtlpLowFragHeapFree
Front-End
10. Windows memory allocator
• HEAP can be divide into
• Process Heap
• Default heap
• The heap shared by the entire process, it will be used when you use
windows API
• Stored in _PEB
• Used in CRT function
• Stored in crt_heap
12. Windows memory allocator
• Core data structure
• _HEAP_ENTRY (chunk)
• The basic structure of memory allocator
• It is different in front-end and back-end, but it use same name.
13. Windows memory allocator
• _HEAP_ENTRY (chunk)
data
chunk header
chunk header
data
_HEAP
chunk header
.
.
.
malloc return value
14. Windows memory allocator
• Core data structure
• _HEAP
• The core structure of memory allocator, it is used to manage the
heap.
• Each heap correspond to a _HEAP structure, usually at the
beginning of the heap
15. Windows memory allocator
• _HEAP
• EncodeFlagMask
• It will be set to 0x100000 after
heap initialization. It’s used to
determine whether to encode the
header of the chunk in the heap
• Encoding (_HEAP_ENTRY)
• It’s used to do xor with chunk
header
…
EncodeFlagMask0x7c
0x80
0x138
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
0x150
0x198
FrontEndHeapUsageData0x1a8
…
16. Windows memory allocator
• _HEAP
• BlocksIndex (_HEAP_LIST_LOOKUP_)
• The core structure in back-end
allocator used to manage chunks.
• FreeList (_HEAP_ENTRY)
• A linked list used to collect all freed
chunk in back-end
• Similar as unsorted bin in libc
• Sorted list
…
EncodeFlagMask0x7c
0x80
0x138
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
0x150
0x198
FrontEndHeapUsageData0x1a8
…
17. Windows memory allocator
• _HEAP
• FrontEndHeap
• A pointer pointed to the structure of
front-end heap
• FrontEndHeapUsageData
• Record the number of chunks used
by various sizes.
• When it reaches a certain level, it
will enable the Front-End allocator
of the corresponding chunk.
…
EncodeFlagMask0x7c
0x80
0x138
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
0x150
0x198
FrontEndHeapUsageData0x1a8
…
19. Nt heap
• Nt Heap
• Back-End
• Data structure
• Memory allocation mechanism
20. Windows memory allocator
• _HEAP_ENTRY (chunk)
• Divided into
• Allocated chunk
• Freed chunk
• VirtualAlloc chunk
21. Nt heap
• _HEAP_ENTRY (chunk)
• PreviousBlockPrivateData
• The data of the previous chunk,
because chunk must be aligned to a
multiple of 0x10
• Size
• The size of chunk.
• The value is right shift by 4 bits.
User Data
PreviousBlockPrivateData
(8byte)
Size (2byte)
Flag (1byte)
SmallTagIndex (1byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
Inused
22. Nt heap
• _HEAP_ENTRY (chunk)
• Flag
• Indicates whether the chunk is busy
• SmallTagIndex
• Checksum is the xor of the first three
bytes
• It will be used to verify the header of
chunk
User Data
PreviousBlockPrivateData
(8byte)
Size (2byte)
Flag (1byte)
SmallTagIndex (1byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
Inused
xor
23. Nt heap
• _HEAP_ENTRY (chunk)
• PreviousSize
• The size of previous chunk.
• The value is right shift by 4 bits.
User Data
PreviousBlockPrivateData
(8byte)
Size (2byte)
Flag (1byte)
SmallTagIndex (1byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
Inused
24. Nt heap
• _HEAP_ENTRY (chunk)
• Unusedbyte
• The remaining size of chunk after
allocation
• It can be used to determine the status
of chunk (front-end or back-end)
• User Data
• The data used by user
User Data
PreviousBlockPrivateData
(8byte)
Size (2byte)
Flag (1byte)
SmallTagIndex (1byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
Inused
25. Nt heap
• _HEAP_ENTRY (chunk)
• Flink
• Point to the next chunk in the linked list
• Blink
• Point to the previous chunk in the
linked list
• Unusedbyte
• Must be zero
User Data
PreviousBlockPrivateData
(8byte)
Size (2byte)
Flag (1byte)
SmallTagIndex (1byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
freed
Flink
Blink
26. Nt heap
• _HEAP_VIRTUAL_ALLOC_ENTRY (mmap
chunk)
• Flink
• Point to the next chunk of VirtualAlloc
• Blink
• Point to the previous chunk of
VirtualAlloc
User Data
Size (2byte)
Flag (1byte)
SmallTagIndex (1byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
inused
Flink
Blink
…
27. Nt heap
• _HEAP_VIRTUAL_ALLOC_ENTRY (mmap
chunk)
• Size
• The size here refers to unused size
without shifting
• Unusedbyte
• Must be 4
User Data
Size (2byte)
Flag (1byte)
SmallTagIndex (1byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
inused
Flink
Blink
…
28. Nt heap
• FreeLists (_HEAP_ENTRY)
• After free a chunk, it will be placed in FreeLists and will be inserted in
FreeLists according to the size.
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x110)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x160)
PreviousBlockPrivateData
30. Nt heap
• Remark
• About header encoding
• Every chunk header will be xor with _HEAP->Encoding
• It will be verified when it is decoded
• The verification method is to check whether the checksum is
correct.
• The xor of the first three bytes and compare with fourth byte.
31. Nt heap
• BlocksIndex (_HEAP_LIST_LOOKUP)
• It is mainly used to manage freed chunks of various sizes, so that it can
quickly find suitable chunks.
32. Nt heap
• BlocksIndex (_HEAP_LIST_LOOKUP)
• ExtendedLookup (_HEAP_LIST_LOOKUP)
• Point to next ExtendedLookup
• The next BlocksIndex will manage larger
chunks
• ArraySize
• The max chunk size that will be managed by
the BlocksIndex.
• The first BlocksIndex ArraySize will by 0x80
(Actually is 0x800)
BlocksIndex
ExtendedLookup0x0
ArraySize0x8
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
0x10
0x14
BaseIndex0x18
ListHead
ListsInUseUlong
ListHint
0x20
0x28
0x30
33. Nt heap
• BlocksIndex (_HEAP_LIST_LOOKUP)
• ItemCount
• The number of chunks in the
BlocksIndex
• OutofRangeItems
• The number of chunks that exceed
the size managed by this
BlocksIndex
BlocksIndex
ExtendedLookup0x0
ArraySize0x8
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
0x10
0x14
BaseIndex0x18
ListHead
ListsInUseUlong
ListHint
0x20
0x28
0x30
34. Nt heap
• BlocksIndex (_HEAP_LIST_LOOKUP)
• BaseIndex
• The starting index of the chunk in the
Blocksindex.
• It is used to find a suitable freed chunk in
ListHint
• The next BaseIndex of next BlocksIndex is the
maximum value of current BaseIndex.
• ListHead (_HEAP_ENTRY)
• FreeList 的 Head
BlocksIndex
ExtendedLookup0x0
ArraySize0x8
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
0x10
0x14
BaseIndex0x18
ListHead
ListsInUseUlong
ListHint
0x20
0x28
0x30
35. Nt heap
• BlocksIndex (_HEAP_LIST_LOOKUP)
• ListsInUseUlong
• Used to determine whether there is a suitable
chunk in ListHint, which is a bitmap
• ListHint
• Important structure in back-end.
• A pointer array which point to the corresponding
size of chunk array.
• The goal is to find the suitable chunk faster.
• The interval of chunk size is 0x10
BlocksIndex
ExtendedLookup0x0
ArraySize0x8
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
0x10
0x14
BaseIndex0x18
ListHead
ListsInUseUlong
ListHint
0x20
0x28
0x30
37. Nt heap
• Nt Heap
• Back-End
• Data structure
• Memory allocation mechanism
38. Nt heap
• Allocate (RtlpAllocateHeap)
• It can be divided into
• Size <= 0x4000
• 0x4000 < size <= 0xff000
• Size > 0xff000
39. Nt heap
• Allocate (RtlpAllocateHeap)
• Size <= 0x4000
• The memory allocation is implemented in RtlpAllocateHeap
• First, it will check whether FrontEndHeapStatusBitmap corresponds to the
size is set (which indicates if LFH is enabled)
• If not, add 0x21 to the corresponding FrontEndHeapUsageData
• And check if the value exceeds 0xff00 or (& 0x1f) is larger than 0x10
• If true, it will enable LFH.
40. Nt heap
• Allocate (RtlpAllocateHeap)
• Size <= 0x4000
• Next, it will check whether ListHint corresponds to the size has a value. If true, it will take
the chunk in ListHint first.
• If there is a suitable chunk on the ListHint, remove the ListHint, and see whether the size
of chunk's Flink is the same size.
• If true, replace the ListHint with Flink
• If not, clear the ListHint.
• Finally, unlink the chunk to remove the chunk from the linked list and return it to user.
41. Nt heap
• Allocate (RtlpAllocateHeap)
• Size <= 0x4000
• If there is no suitable chunk
• Search from the larger ListHint. If it finds a large one, remove it
from the ListHint.
• Then split the chunk and insert remaining chunk into freelist and
put into ListHint.
42. Nt heap
• Allocate (RtlpAllocateHeap)
• Size <= 0x4000
• If there is no suitable chunk in FreeList
• Try ExtendHeap to increase heap space, then take the chunk from
it
43. Nt heap
• Allocate (RtlpAllocateHeap)
• 0x4000 < size <= 0xff000
• Everything is similar except without LFH-related operations
44. Nt heap
• Allocate (RtlpAllocateHeap)
• Size > 0xff000 (VirtualMemoryThreshold << 4)
• Use ZwAllocateVirtualMemory directly
• Similar to mmap, it will allocate large memory block , and will be
inserted into _HEAP->VirtualAllocdBlocks
• _HEAP->VirtualAllocdBlocks is linked list used to collect all
VirtualAllocate chunk in back-end
45. Nt heap
• Free (RtlpFreeHeap)
• Divide into
• Size <= 0xff000
• Size > 0xff000
46. Nt heap
• Free (RtlpFreeHeap)
• Size <= 0xff000
• It will check the alignment first and use the unused byte to determine the
chunk state
• If LFH is disable, decrease 1 to the corresponding
FrontEndHeapUsageData
• Then it will check whether the previous chunk or next chunk is freed. If it is
freed, then coalesce them.
• Unlink the coalesced chunk and remove from ListHint.
47. Nt heap
• Free (RtlpFreeHeap)
• Size <= 0xff000
• After the coalescence, update size & prevsize, and check whether it
is the front or last of FreeList. If true, then insert into FreeList. If not,
insert into ListHint and update it.
• It will check the linked list integrity when inserting
• But this check won’t terminate the process.
63. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Update
prevchunk
and next chunk
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x18)
Flag (0x0)
SmallTagIndex (0x7)
Prevchunk->size =
0x11 + Prevchunk->size(7)
R->Prevsize = 0x18
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
64. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check
next chunk
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x18)
Flag (0x0)
SmallTagIndex (0x7)
Check if next chunk
is freed
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
65. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Find suitable
BlocksIndex
For P
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x18)
Flag (0x0)
SmallTagIndex (0x7)
Check
P->Size < ArraySize
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
66. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Search
insert
point
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x18)
Flag (0x0)
SmallTagIndex (0x7)
Check
P->size <
ListHead->Blink->Size
P->size <
ListHead->Flink->Size
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
67. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Insert
linked list
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x18)
Flag (0x0)
SmallTagIndex (0x7)
Check
S->Blink->Flink
== S
If not pass it will not
abort
But it will not unlink
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
68. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Update
ListHint
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x18)
Flag (0x0)
SmallTagIndex (0x7)
If LintHint[0x18] == NULL
LintHint[0x18] = P
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
FlinkListHint[0x18]
69. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Update
header
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x18)
Flag (0x0)
SmallTagIndex (0x18)
SmallTagIndex =
(size >> 8) ^
(size & 0xff) ^
Flag
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
FlinkListHint[0x18]
70. ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Encode
header
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0xda)
Flag (0xab)
SmallTagIndex (0x41)
P->header ^
_HEAP->Encoding
P
Flink
Blink
Chunk header (0x180)
PreviousBlockPrivate
FlinkListHint[0x18]
71. Nt heap
• Free (RtlpFreeHeap)
• Size > 0xff000
• Check the linked list integrity and remove from _HEAP-
>VirtualAllocdBlocks
• Then use RtlpSecMemFreeVirtualMemory to munmap the chunk
72. Back-End Exploitation
• Unlink
• Similar bypass method in Linux.
• In short, use the behavior of removing nodes from linked list.
• It should be noted that the checksum must correct when decoding
chunk.
• The good thing is that Flink and Blink are directly point to UserData,
that is, you don’t have to forge chunk header
77. A
A
Chunk header (0x110)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
UAF
T
A
78. A
A
Chunk header (0x110)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
Free(Q)
T
A
79. Q
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
A
ListHead
QListHint[0x11]
free(S)
Update ListHint
80. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
A
S
SListHint[0x11]
Q
ListHead
81. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
A
S
SListHint[0x11]
Q
ListHead
Let’s corrupt the heap !
82. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead
free(P)
83. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead
Check next chunk
is free
84. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead
Decode
chunk Q
85. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead(&Q-8)->Blink
==
(&Q)->Flink
== Q
86. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead(&Q-8)->Blink
==
(&Q)->Flink
== Q
Flink
Blink
87. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead(&Q-8)->Blink
==
(&Q)->Flink
== Q
Flink
Blink
88. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead*(&Q)
==
*(&Q)
== Q
89. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead*(&Q)
==
*(&Q)
== Q
Pass the check !!
90. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead
Find
BlockIndex
91. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead
Check
ListHint[0x11]
92. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHeadBecause S != Q
it will not replace
ListHint with Q
93. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
Data Pointer
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead
Unlink !!
Q->Blink->Flink
= Q->Flink
Flink
Blink
94. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
&Q - 8
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHeadUnlink !!
Q = &Q-8
95. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
&Q - 8
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHead
Unlink !!
Q->Flink->Blink
= Q->Blink
Flink
Blink
96. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHeadUnlink !!
Q = &Q
97. S
A
Chunk header (0x110)
PreviousBlockPrivate
Q
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
P
Q
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
&Q - 8
&Q
SListHint[0x11]
Q
ListHeadUpdate
chunk size
98. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHeadUpdate
chunk size
P
99. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHead
Search insert point
P
100. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHeadFind the last one
And decode it
P
101. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHead
P
Find the first one
And decode it
102. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHeadIt want to insert
in front of A
P
103. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHead
Check
A->Blink->Flink
== A
P
104. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHead
Check
Q->Flink
== A
P
105. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHeadFailed
but not aborting
It will not insert
P
106. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHead
Update
ListHint
P
107. S
A
Chunk header (0x220)
PreviousBlockPrivate
Chunk header(0x50)
PreviousBlockPrivat
S
Chunk header(0x110)
PreviousBlockPrivat
R
S
P
&Q
R
S
T
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
BlockIndex
ListHint
T
A
SListHint[0x11]
Q
ListHead
P
PListHint[0x22]
108. Back-End Exploitation
• Edit Q
• We can overwrite the pointer around
Q
• Finally, we can do arbitrary
memory reading and writing.
P
&Q
R
S
T
109. Back-End Exploitation
• Edit Q
• We can overwrite the pointer around
Q
• Finally, we can do arbitrary
memory reading and writing.
• We can overwrite Target 1 - 4
P
Target 1
Target 2
Target 3
Target 4
111. Back-End Exploitation
• After arbitrary memory reading and writing
• Leak
• kernelbase
• KERNELBASE!BasepFilterInfo
• Stack address
112. Back-End Exploitation
• After arbitrary memory reading and writing
• Leak
• ntdll.dll
• _HEAP_LOCK
• _HEAP->LockVariable.Lock
• CriticalSection->DebugInfo
• Point to ntdll
113. Back-End Exploitation
• After arbitrary memory reading and writing
• Leak
• ntdll!PebLdr
• _PEB_LDR_DATA
• You can find all the location of dll
• However the drawback is that the last two byte may be 0.
• You can find the binary base first and find kernel32 from IAT
115. Back-End Exploitation
• After arbitrary memory reading and writing
• Leak
• Kernel32
• Important dll
• Many useful function(CreateFile, ReadFile,WriteFile)
• IAT
• Find kernelbase.dll
116. Back-End Exploitation
• After arbitrary memory reading and writing
• Leak
• kernelbase
• KERNELBASE!BasepFilterInfo
• Point to the structure on heap
• You have high probability to find stack pointer in the structure
• https://j00ru.vexillium.org/2016/07/disclosing-stack-data-from-the-default-
heap-on-windows/
117. Back-End Exploitation
• After arbitrary memory reading and writing
• Leak
• If there is no stack address in BasepFilterInfo
• You can find stack address in TEB which usually locate one page
before or after PEB
118. Back-End Exploitation
• After arbitrary memory reading and writing
• Write
• Return address
• Control RIP
• ROP to VirtualProtect/VirtualAlloc
• Jmp to shellcode
123. LFH
• FrontEndHeap (_LFH_HEAP)
• HEAP (_HEAP)
• Point to the corresponding _HEAP
• Buckets (_HEAP_BUCKET)
• An array to find the malloc size
corresponding to the block size
…
Heap0x18
0x2a4
…
Buckets
SegmentInfoArray
…
…
LocalData
0x4a8
0xcc0
124. LFH
• FrontEndHeap (_LFH_HEAP)
• SegmentInfoArray
(_HEAP_LOCAL_SEGMENT_INFO)
• _HEAP_LOCAL_SEGMENT_INFO array
• Different sizes correspond to different
Segment_info structures, to manage the
information of the corresponding Subsegment.
• LocalData (_HEAP_LOCAL_DATA)
• One of the fields points to the LFH itself, which
is usually used to retrieve the LFH.
…
Heap0x18
…
Buckets
SegmentInfoArray
…
…
LocalData
0x2a4
0x4a8
0xcc0
126. LFH
• SegmentInfoArray
(_HEAP_LOCAL_SEGMENT_INFO)
• LocalData (_HEAP_LOCAL_DATA)
• Corresponding to _LFH_HEAP-
>LocalData to retrieve _LFH_HEAP
from SegmentInfo
• BucketIndex
• The index in Buckets[]
LocalData
SegmentInfoArray[x]
ActiveSubsegment
CachedItems
…
BucketIndex
…
127. LFH
• SegmentInfoArray
(_HEAP_LOCAL_SEGMENT_INFO)
• ActiveSubsegment (_HEAP_SUBSEGMENT)
• Very important structure
• Corresponding to the assigned Subsegment
• To maintain Userblock
• Record number of remaining chunk
• The maximum number of chunk in
Userblock
SegmentInfoArray[x]
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
128. LFH
• SegmentInfoArray
(_HEAP_LOCAL_SEGMENT_INFO)
• CachedItems (_HEAP_SUBSEGMENT)
• _HEAP_SUBSEGMENT array
• Stored the available Subsegment
correspond to the SegmentInfo
• When the ActiveSubsegment used
up, it will reload from CachedItems.
SegmentInfoArray[x]
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
130. LFH
• ActiveSubsegment (_HEAP_SUBSEGMENT)
• LocalInfo
(_HEAP_LOCAL_SEGMENT_INFO)
• Point back to corresponding
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
ActiveSubsegment
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
0x0
0x8
0x20
0x24
0x28
0x2a
131. LFH
• ActiveSubsegment (_HEAP_SUBSEGMENT)
• UserBlock (_HEAP_USERDATA_HEADER)
• Memory pool of LFH
• That is, the location of chunk (Block)
• Some metadata will manage the
chunks at the beginning of UserBlock
• Important !
LocalInfo
ActiveSubsegment
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
0x0
0x8
0x20
0x24
0x28
0x2a
132. LFH
• ActiveSubsegment (_HEAP_SUBSEGMENT)
• AggregateExchg (_INTERLOCK_SEQ)
• To indicate remaining amount of
freed chunk in Userblock
• LFH uses it to determine if it should
allocate from this UserBlock
LocalInfo
ActiveSubsegment
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
0x0
0x8
0x20
0x24
0x28
0x2a
133. LFH
• ActiveSubsegment (_HEAP_SUBSEGMENT)
• BlockSize
• The size of each block (chunk) in the
UserBlock
• BlockCount
• The number of blocks in the UserBlock
• SizeIndex
• The SizeIndex corresponding to the
UserBlock
LocalInfo
ActiveSubsegment
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
0x0
0x8
0x20
0x24
0x28
0x2a
134. LFH
• AggregateExchg (_INTERLOCK_SEQ)
• Depth
• The remaining amount of freed chunk in
UserBlock
• Lock
• Just a Lock
AggregateExchg
Depth0x0
Hint (15bit)
Lock (1bit)
0x8
135. LFH
• UserBlock (_HEAP_USERDATA_HEADER)
• SubSegment
• Point to corresponding Subsegment
• EncodeOffsets
• To verify chunk header integrity
• BusyBitmap
• Indicate which chunk is being used
SubSegment
UserBlock
…
EncodedOffsets
BusyBitmap
0x8
0x18
0x20
chunk header
chunk header
chunk header
137. LFH
• _HEAP_ENTRY (chunk)
• SubSegmentCode
• Encoded metadata to retrieve the
location of UserBlock
• PreviousSize
• The index of the chunk in UserBlock
User Data
PreviousBlockPrivateData
(8byte)
SubSegmentCode (4byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
Inused
138. LFH
• _HEAP_ENTRY (chunk)
• Unusedbyte
• Unusedbyte & 0x80 must be true
• To indicate it is LFH chunk
User Data
PreviousBlockPrivateData
(8byte)
SubSegmentCode (4byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
Inused
139. LFH
• _HEAP_ENTRY (chunk)
• Unusedbytes
• Must be 0x80
• To indicate it is LFH freed chunk
User Data
PreviousBlockPrivateData
(8byte)
SubSegmentCode (4byte)
PreviousSize (2byte)
SegmentOffset (1byte)
Unusedbyte (1byte)
Freed
140. LFH
• Remark
• About EncodedOffsets
• EncodedOffsets is xor of the following values
• (sizeof(userblock header) | (BlockUnit*0x10 << 16))
• LFHkey
• Userblock address
• _LFH_HEAP address
141. LFH
• Remark
• About LFH header encoding
• The chunk header will xor with following values when initialization
• _HEAP address
• LFHkey
• Chunk address >> 4
• ((chunk address) - (UserBlock address)) << 12
144. Windows memory allocator
• Nt Heap
• Front-End
• Initialization
• If FrontEndHeapUsageData[x] & 0x1f > 0x10, LFH will be initialized in next allocation
• It will ExtendFrontEndUsageData and create new BlocksIndex (0x80-0x400)
• Create FrontEndHeap
• Initialize SegmentInfoArrays[idx]
• It will start using front-end allocator from next allocation with same size
145. Windows memory allocator
• LFH(Initialization)
• malloc(0x40) * 16
FrontEndHeapUsageData
…
0x210
The range of LFH is index
from 0x0 to 0x80
147. Windows memory allocator
• LFH(Initialization)
FrontEndHeapUsageData
…
0x231
heap->CompatibilityFlag |= 0x20000000
After setting this flag, it will initialize
LFH in the next allocation
149. Windows memory allocator
• LFH(Initialization)
• malloc(0x40) (18th)
• ExtendFrontEndUsageData and create new BlocksIndex
(0x80-0x400)
• The range of LFH is modified to index from 0x0 to
0x400
• Create and initialize FrontEndHeap (mmap)
• initialize SegmentInfoArrays[idx]
• Assign SegmentInfoArrays[BucketIndex] to
segmentInfo
FrontEndHeapUsageData
…
0x4
152. Windows memory allocator
• LFH(Initialization)
• malloc(0x40) (19th)
• Allocate Userblock and initialize every
chunk.
• Set the corresponding ActiveSubsegment
to the UserBlock
• Randomly return chunk to user
Userblock metadata
Chunk 00
Chunk 01
…
Chunk MaxBlockCount
154. Windows memory allocator
• LFH
• Allocate (RtlpLowFragHeapAllocFromContext)
• It will check whether ActiveSubsegment has chunk available.
• Check ActiveSubsegment->depth
• If not, it will search from CachedItem, and replace ActiveSubsegment
with CachedItem’s SubSegment if available.
162. Windows memory allocator
• LFH
• Allocate (RtlpLowFragHeapAllocFromContext)
• Retrieve RtlpLowFragHeapRandomData[x]
• It will retrieve the value from RtlpLowFragHeapRandomData[x+1] next
round.
• x is 1 byte, x = rand() %256 after 256 rounds
• RtlpLowFragHeapRandomData is a 256-byte array filled with random value
• The range of random value is 0x0 - 0x7f
163. Windows memory allocator
• LFH
• Allocate (RtlpLowFragHeapAllocFromContext)
• Finally, the index of chunk is
• RtlpLowFragHeapRandomData[x]*maxidx >> 7
• Take the nearest chunk if collision
• Check (unused byte & 0x3f) !=0 (indicate chunk is freed)
• Modify index and unused byte in header and return to user
167. Windows memory allocator
• LFH
• Free (RtlFreeHeap)
• Update unused byte in chunk header
• Find the index of the Chunk and reset Userblock->BusyBitmap
• Update ActiveSubsegment->AggregateExchg
• If the free chunk is not belong to ActiveSubsegment, it will try to put
into cachedItems
175. LFH Exploitation
• Reuse attack
• If we have Use After Free
• Because of randomness of LFH, we can not predict the next chunk.
• We can fill up UserBlock and then free one of them, it will return
same chunk in next allocation with same size.