Windows 10 Nt Heap Exploitation (English version)

A
Windows Heap Exploitation
Angelboy
Windows Heap Exploitation
• Windows Memory Allocator

• NT heap

• BackEnd

• Exploitation

• FrontEnd

• LowFragmentationHeap

• Exploitation
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.
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
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.
Windows memory allocator
• Overview
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
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
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
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
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
Windows memory allocator
• HEAP can be divide into

• Private heap

• Create by HeapCreate
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.
Windows memory allocator
• _HEAP_ENTRY (chunk)
data
chunk header
chunk header
data
_HEAP
chunk header
.
.
.
malloc return value
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
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
…
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
…
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
…
Windows memory allocator
• Nt Heap

• Back-End

• Front-End
Nt heap
• Nt Heap

• Back-End

• Data structure

• Memory allocation mechanism
Windows memory allocator
• _HEAP_ENTRY (chunk)

• Divided into

• Allocated chunk

• Freed chunk

• VirtualAlloc chunk
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
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
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
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
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
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
…
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
…
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
Nt heap
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x110)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x160)
PreviousBlockPrivateDat
…
EncodeFlagMask0x7c
0x80
0x138
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
0x150
0x198
FrontEndHeapUsageData0x1a8
…
Flink
Blink
_HEAP
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.
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.
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
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
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
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
…
EncodeFlagMask
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
FrontEndHeapUsageDat
…
_HEAP
BlocksIndex
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Flink
Blink
Chunk header (0x110)
PreviousBlockPrivate
Flink
Blink
Chunk header(0x160)
PreviousBlockPrivat
ListHint
Flink
Flink
Flink
ListHint[7]
ListHint[0x11]
ListHint[0x16]
000001…1…1000000000
ListsInUseUlong
Nt heap
• Nt Heap

• Back-End

• Data structure

• Memory allocation mechanism
Nt heap
• Allocate (RtlpAllocateHeap)

• It can be divided into

• Size <= 0x4000

• 0x4000 < size <= 0xff000

• Size > 0xff000
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.
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.
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.
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
Nt heap
• Allocate (RtlpAllocateHeap)

• 0x4000 < size <= 0xff000

• Everything is similar except without LFH-related operations
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
Nt heap
• Free (RtlpFreeHeap)

• Divide into

• Size <= 0xff000 

• Size > 0xff000
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.
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.
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Free(Q)
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Find Prevchunk
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Prevchunk =
Chunk address
-
(prevsize << 4)
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Find Prevchunk
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Prevchunk =
chunk addr - 0x70
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Decode prevchunk

header
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check checksum
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
SmallTagInex ==

(size & 0xff)
xor
(size >> 8)
xor
Flag
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check checksum
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
7 ==

0x7^0x0^0x0
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check

linked list
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
P->Flink->Blink == 

P->Blink->Flink == 

P
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Find 

BlocksIndex
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Find suitable 

BlocksIndex
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
Check
P->size < ArraySize
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check

ListHint
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
Check
ListHint[7] ==
Prevchunk
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check

ListHint
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
Check
prevchunk->Flink ==
ListHead
If true, update

ListHint
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check

ListHint[7]->Flink
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
decode
prevchunk->Flink
And check
the checksum
Because the previous
slide is not true, it

will check the size

of Flink
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Check

ListHint[7]->Flink
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
Size == 

prevchunk->Flink->size
If true, replace ListHint

with Flink

ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Update

ListHint[7]
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
ListHint[7] =

prevchunk->Flink
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
Flink
Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivate
Chunk header (0x110)
PreviousBlockPrivate
Chunk header(0x110)
PreviousBlockPrivat
FlinkListHint[7]
Flink
Blink
Chunk header(0x70)
PreviousBlockPrivat
merge chunk
P
Q
R
S
Unlink

prevchunk
Size (0x11)
Flag (0x1)
SmallTagIndex (0x10)
Prevsize (0x7)
Size (0x7)
Flag (0x0)
SmallTagIndex (0x7)
Prevchunk->Blink->Flink

= Prevchunk->Flink

Prevchunk->Flink->Blink
= Prevchunk->Blink
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
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
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
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
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
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]
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]
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]
Nt heap
• Free (RtlpFreeHeap)

• Size > 0xff000 

• Check the linked list integrity and remove from _HEAP-
>VirtualAllocdBlocks

• Then use RtlpSecMemFreeVirtualMemory to munmap the chunk
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
Back-End Exploitation
• Unlink

• Q->Blink->Flink = Q->Flink

• Q->Flink->Blink = Q->Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x110)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x160)
PreviousBlockPrivateData
QP R
Back-End Exploitation
• Unlink

• Q->Blink->Flink = Q->Flink

• Q->Flink->Blink = Q->Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x110)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x160)
PreviousBlockPrivateData
QP R
Back-End Exploitation
• Unlink

• Q->Blink->Flink = Q->Flink

• Q->Flink->Blink = Q->Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x110)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x160)
PreviousBlockPrivateData
QP R
Back-End Exploitation
• Unlink

• Q->Blink->Flink = Q->Flink

• Q->Flink->Blink = Q->Blink
Flink
Blink
Chunk header (0x70)
PreviousBlockPrivateData
Flink
Blink
Chunk header (0x160)
PreviousBlockPrivateData
QP R
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
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
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
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
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 !
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)
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
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
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
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
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
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
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 !!
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
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]
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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]
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
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
Back-End Exploitation
• After arbitrary memory reading and writing

• Leak

• ntdll.dll

• PebLdr

• binary address

• Kernel32.dll
Back-End Exploitation
• After arbitrary memory reading and writing

• Leak

• kernelbase

• KERNELBASE!BasepFilterInfo

• Stack address
Back-End Exploitation
• After arbitrary memory reading and writing

• Leak

• ntdll.dll

• _HEAP_LOCK

• _HEAP->LockVariable.Lock

• CriticalSection->DebugInfo

• Point to ntdll
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
Back-End Exploitation
• After arbitrary memory reading and writing

• Leak

• BinaryBase

• Find kernel32 from IAT
Back-End Exploitation
• After arbitrary memory reading and writing

• Leak

• Kernel32

• Important dll

• Many useful function(CreateFile, ReadFile,WriteFile) 

• IAT

• Find kernelbase.dll
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/
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
Back-End Exploitation
• After arbitrary memory reading and writing

• Write 

• Return address

• Control RIP

• ROP to VirtualProtect/VirtualAlloc

• Jmp to shellcode
Windows memory allocator
• Nt Heap

• Back-End

• Front-End
Windows memory allocator
• Nt Heap

• Front-End

• Commonly use in win10 

• LowFragmentationHeap

• Only enable in non-debug mode

• Size < 0x4000
Windows memory allocator
• Nt Heap

• Front-End

• Data Structure

• Memory allocation mechanism
Windows memory allocator
• Nt Heap

• Front-End

• Data Structure

• Memory allocation mechanism
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
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
LFH
• Buckets (_HEAP_BUCKET)

• BlockUnits

• The block size >> 4

• SizeIndex

• Required size >> 4
BlockUnits
Buckets
SizeIndex
…
BlockUnits
SizeIndex
…
…
…
Buckets[0]
Buckets[1]
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
…
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
…
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
…
LFH
…
Heap
…
…
…
LocalData
0x18
0x2a4
0x4a8
0xcc0
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
…
EncodeFlagMask
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
FrontEndHeapUsageData
…
_HEAP
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
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
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
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
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
LFH
• AggregateExchg (_INTERLOCK_SEQ)

• Depth

• The remaining amount of freed chunk in
UserBlock

• Lock

• Just a Lock
AggregateExchg
Depth0x0
Hint (15bit)
Lock (1bit)
0x8
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
LFH
• UserBlock (_HEAP_USERDATA_HEADER)

• Block (chunk)

• The allocated memory return to user.
SubSegment
UserBlock
…
EncodedOffsets
BusyBitmap
0x8
0x18
0x20
chunk header
chunk header
chunk header
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
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
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
LFH
• Remark

• About EncodedOffsets

• EncodedOffsets is xor of the following values

• (sizeof(userblock header) | (BlockUnit*0x10 << 16))

• LFHkey

• Userblock address

• _LFH_HEAP address
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
LFH
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Windows memory allocator
• Nt Heap

• Front-End

• Data Structure

• Memory allocation mechanism
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
Windows memory allocator
• LFH(Initialization)

• malloc(0x40) * 16
FrontEndHeapUsageData
…
0x210
The range of LFH is index
from 0x0 to 0x80
Windows memory allocator
• LFH(Initialization)

• malloc(0x40) (17th)
FrontEndHeapUsageData
…
0x231 0x231 & 0x1f > 0x10
Windows memory allocator
• LFH(Initialization)
FrontEndHeapUsageData
…
0x231
heap->CompatibilityFlag |= 0x20000000
After setting this flag, it will initialize

LFH in the next allocation
Windows memory allocator
…
EncodeFlagMask
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
FrontEndHeapUsageData
…
_HEAP
FrontEndHeapUsageData
0x231
BlocksIndex
ExtendedLookup
ArraySize
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex
ListHead
ListsInUseUlong
ListHint
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
Windows memory allocator
…
EncodeFlagMask
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
FrontEndHeapUsageData
…
_HEAP
FrontEndHeapUsageData
0x251 0x4
BlocksIndex
ExtendedLookup
ArraySize(0x80)
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex (0x0)
ListHead
ListsInUseUlong
ListHint
BlocksIndex
ExtendedLookup
ArraySize (0x400)
…
ItemCount (4 bytes)
OutofRangeItems (4 bytes)
BaseIndex (0x80)
ListHead
ListsInUseUlong
ListHint
Windows memory allocator
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
…
EncodeFlagMask
Encoding
…
BlocksIndex
…
FreeList
…
FrontEndHeap
…
FrontEndHeapUsageData
…
_HEAP
FrontEndHeapUsageData
0x251 0x4
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
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
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.
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Find SegementIfoArray by bucket->SizeIndex
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Find SegementIfoArray by bucket->SizeIndex
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Check ActiveSubsegment
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Check ActiveSubsegment
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Check ArgregateExchg.Depth not 0
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Check ArgregateExchg.Depth not 0
…
Heap
…
…
…
LocalData
Buckets[x]
SegmentInfoArray[x]
BlockUnits
SizeIndex
…
_LFH_HEAP
_HEAP_BUCKET
_HEAP_LOCAL_SEGMENT_INFO
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
LocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
Check Userblock
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
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
….
….
….
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_HEAP_USERDATA_HEADER
• Get an index

• RtlpLowFragHeapRandomData[x]*maxidx >> 7

• Check if the BusyBitmap correspond to index is
0

• Return the chunk if true

• Otherwise take the next nearest chunk
chunk header
….
….
….
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_HEAP_USERDATA_HEADER
• If the index is inused 

• Take next nearest chunk

• Set the bitmap to 1
chunk header
….
….
….
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_HEAP_USERDATA_HEADER
chunk header
• If the index is inused 

• Take next nearest chunk

• Set the bitmap to 1
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
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
• Free

• Find UserBlock by chunk
header
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
• Free

• Find UserBlock by chunk
header

• Find corresponding
SubSegment
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
• Free

• Find UserBlock by chunk
header

• Find corresponding
SubSegment

• Assign unused byte to
0x80

• Clear the bitmap

• Update AggregateExchg
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
• Free

• Find UserBlock by chunk
header

• Find corresponding
SubSegment

• Assign unused byte to
0x80

• Clear the bitmap

• Update AggregateExchg
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
Depth
Hint (15bit)
Lock (1bit)
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_INTERLOCK_SEQ
_HEAP_USERDATA_HEADER
• Free

• Find UserBlock by chunk
header

• Find corresponding
SubSegment

• Assign unused byte to
0x80

• Clear the bitmap

• Update AggregateExchg
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_HEAP_USERDATA_HEADERLocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
_HEAP_SUBSEGMENT
Depth (1)
Hint (15bit)
Lock (1bit)
_INTERLOCK_SEQ
CachedItems
ActiveSubsegment 

is not equivalent to

SubSegment of free

chunk
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
_HEAP_SUBSEGMENT
SubSegment
…
EncodedOffsets
BusyBitmap
chunk header
chunk header
chunk header
_HEAP_USERDATA_HEADERLocalData
ActiveSubsegment
CachedItems
…
BucketIndex
…
LocalInfo
UserBlock
…
AggregateExchg
BlockSzie
BlockCount
…
SizeIndex
…
_HEAP_SUBSEGMENT
Depth (1)
Hint (15bit)
Lock (1bit)
_INTERLOCK_SEQ
CachedItems
CachedItems[0]
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.
LFH Exploitation
• normal case

• malloc(sizeof(A))
Userblock header
LFH Exploitation
• normal case

• malloc(sizeof(B))
Userblock header
fptr
LFH Exploitation
• normal case

• free(A)
Userblock header B
fptr
LFH Exploitation
• normal case

• malloc(sizeof(A))
Userblock header B
fptr
LFH Exploitation
• normal case

• malloc(sizeof(B))
Userblock header B
fptr
LFH Exploitation
• normal case

• malloc(sizeof(B))
Userblock header B
fptr
Hard to use
LFH Exploitation
• Reuse attack 

• malloc(sizeof(A))
Userblock header
LFH Exploitation
• Reuse attack 

• malloc(sizeof(B)) x 6
Userblock header
fptr
LFH Exploitation
• Reuse attack 

• free(A)
Userblock header
B
B B B
fptr B B
LFH Exploitation
• Reuse attack 

• malloc(sizeof(B))
Userblock header
B
B B B
fptr B B
LFH Exploitation
• Reuse attack 

• A->fptr
Userblock header
B
B B B
fptr B B
LFH Exploitation
• Reuse attack 

• A->fptr
Userblock header
B
B B B
fptr B B
Hijack the control flow !
Reference
• https://github.com/saaramar/
35C3_Modern_Windows_Userspace_Exploitation

• http://illmatics.com/Understanding_the_LFH.pdf

• https://github.com/saaramar/Deterministic_LFH
Thank you for listening
angelboy@chroot.org @scwuaptx
1 of 189

Recommended

Reliable Windows Heap Exploits by
Reliable Windows Heap ExploitsReliable Windows Heap Exploits
Reliable Windows Heap Exploitsamiable_indian
3.3K views81 slides
Windows 10 Nt Heap Exploitation (Chinese version) by
Windows 10 Nt Heap Exploitation (Chinese version)Windows 10 Nt Heap Exploitation (Chinese version)
Windows 10 Nt Heap Exploitation (Chinese version)Angel Boy
7.8K views189 slides
Pwning in c++ (basic) by
Pwning in c++ (basic)Pwning in c++ (basic)
Pwning in c++ (basic)Angel Boy
30.6K views83 slides
Play with FILE Structure - Yet Another Binary Exploit Technique by
Play with FILE Structure - Yet Another Binary Exploit TechniquePlay with FILE Structure - Yet Another Binary Exploit Technique
Play with FILE Structure - Yet Another Binary Exploit TechniqueAngel Boy
38.4K views81 slides
Windows Kernel Exploitation : This Time Font hunt you down in 4 bytes by
Windows Kernel Exploitation : This Time Font hunt you down in 4 bytesWindows Kernel Exploitation : This Time Font hunt you down in 4 bytes
Windows Kernel Exploitation : This Time Font hunt you down in 4 bytesPeter Hlavaty
31.1K views50 slides
Kernel Pool by
Kernel PoolKernel Pool
Kernel Poolguest215c4e
1.3K views73 slides

More Related Content

What's hot

DeathNote of Microsoft Windows Kernel by
DeathNote of Microsoft Windows KernelDeathNote of Microsoft Windows Kernel
DeathNote of Microsoft Windows KernelPeter Hlavaty
9.4K views42 slides
You didnt see it’s coming? "Dawn of hardened Windows Kernel" by
You didnt see it’s coming? "Dawn of hardened Windows Kernel" You didnt see it’s coming? "Dawn of hardened Windows Kernel"
You didnt see it’s coming? "Dawn of hardened Windows Kernel" Peter Hlavaty
9.4K views62 slides
How Functions Work by
How Functions WorkHow Functions Work
How Functions WorkSaumil Shah
27.1K views52 slides
Social Engineering the Windows Kernel by James Forshaw by
Social Engineering the Windows Kernel by James ForshawSocial Engineering the Windows Kernel by James Forshaw
Social Engineering the Windows Kernel by James ForshawShakacon
11.6K views61 slides
NTUSTxTDOH - Pwn基礎 2015/12/27 by
NTUSTxTDOH - Pwn基礎 2015/12/27NTUSTxTDOH - Pwn基礎 2015/12/27
NTUSTxTDOH - Pwn基礎 2015/12/27Sheng-Hao Ma
5.3K views215 slides
BlueHat v17 || Out of the Truman Show: VM Escape in VMware Gracefully by
BlueHat v17 || Out of the Truman Show: VM Escape in VMware Gracefully BlueHat v17 || Out of the Truman Show: VM Escape in VMware Gracefully
BlueHat v17 || Out of the Truman Show: VM Escape in VMware Gracefully BlueHat Security Conference
1.8K views53 slides

What's hot(20)

DeathNote of Microsoft Windows Kernel by Peter Hlavaty
DeathNote of Microsoft Windows KernelDeathNote of Microsoft Windows Kernel
DeathNote of Microsoft Windows Kernel
Peter Hlavaty9.4K views
You didnt see it’s coming? "Dawn of hardened Windows Kernel" by Peter Hlavaty
You didnt see it’s coming? "Dawn of hardened Windows Kernel" You didnt see it’s coming? "Dawn of hardened Windows Kernel"
You didnt see it’s coming? "Dawn of hardened Windows Kernel"
Peter Hlavaty9.4K views
How Functions Work by Saumil Shah
How Functions WorkHow Functions Work
How Functions Work
Saumil Shah27.1K views
Social Engineering the Windows Kernel by James Forshaw by Shakacon
Social Engineering the Windows Kernel by James ForshawSocial Engineering the Windows Kernel by James Forshaw
Social Engineering the Windows Kernel by James Forshaw
Shakacon11.6K views
NTUSTxTDOH - Pwn基礎 2015/12/27 by Sheng-Hao Ma
NTUSTxTDOH - Pwn基礎 2015/12/27NTUSTxTDOH - Pwn基礎 2015/12/27
NTUSTxTDOH - Pwn基礎 2015/12/27
Sheng-Hao Ma5.3K views
Linux binary Exploitation - Basic knowledge by Angel Boy
Linux binary Exploitation - Basic knowledgeLinux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledge
Angel Boy3K views
Injection on Steroids: Codeless code injection and 0-day techniques by enSilo
Injection on Steroids: Codeless code injection and 0-day techniquesInjection on Steroids: Codeless code injection and 0-day techniques
Injection on Steroids: Codeless code injection and 0-day techniques
enSilo29.6K views
Linux Binary Exploitation - Heap Exploitation by Angel Boy
Linux Binary Exploitation - Heap Exploitation Linux Binary Exploitation - Heap Exploitation
Linux Binary Exploitation - Heap Exploitation
Angel Boy1.9K views
Ch 6: The Wild World of Windows by Sam Bowne
Ch 6: The Wild World of WindowsCh 6: The Wild World of Windows
Ch 6: The Wild World of Windows
Sam Bowne138 views
CNIT 127 Ch 3: Shellcode by Sam Bowne
CNIT 127 Ch 3: ShellcodeCNIT 127 Ch 3: Shellcode
CNIT 127 Ch 3: Shellcode
Sam Bowne167 views
Tcache Exploitation by Angel Boy
Tcache ExploitationTcache Exploitation
Tcache Exploitation
Angel Boy2.8K views
Page cache in Linux kernel by Adrian Huang
Page cache in Linux kernelPage cache in Linux kernel
Page cache in Linux kernel
Adrian Huang1.5K views
CNIT 127 Ch 8: Windows overflows (Part 1) by Sam Bowne
CNIT 127 Ch 8: Windows overflows (Part 1)CNIT 127 Ch 8: Windows overflows (Part 1)
CNIT 127 Ch 8: Windows overflows (Part 1)
Sam Bowne197 views
CNIT 127: 8: Windows overflows (Part 2) by Sam Bowne
CNIT 127: 8: Windows overflows (Part 2)CNIT 127: 8: Windows overflows (Part 2)
CNIT 127: 8: Windows overflows (Part 2)
Sam Bowne628 views
MacOS memory allocator (libmalloc) Exploitation by Angel Boy
MacOS memory allocator (libmalloc) ExploitationMacOS memory allocator (libmalloc) Exploitation
MacOS memory allocator (libmalloc) Exploitation
Angel Boy4.6K views
CNIT 127 Ch 4: Introduction to format string bugs by Sam Bowne
CNIT 127 Ch 4: Introduction to format string bugsCNIT 127 Ch 4: Introduction to format string bugs
CNIT 127 Ch 4: Introduction to format string bugs
Sam Bowne228 views
Triton and Symbolic execution on GDB@DEF CON China by Wei-Bo Chen
Triton and Symbolic execution on GDB@DEF CON ChinaTriton and Symbolic execution on GDB@DEF CON China
Triton and Symbolic execution on GDB@DEF CON China
Wei-Bo Chen2.2K views
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour by Soroush Dalili
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ BehaviourWAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
Soroush Dalili52.8K views

Similar to Windows 10 Nt Heap Exploitation (English version)

Recon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_he by
Recon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_heRecon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_he
Recon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_heLiang Chen
253 views58 slides
Everything I Ever Learned About JVM Performance Tuning @Twitter by
Everything I Ever Learned About JVM Performance Tuning @TwitterEverything I Ever Learned About JVM Performance Tuning @Twitter
Everything I Ever Learned About JVM Performance Tuning @TwitterAttila Szegedi
110K views62 slides
04 cache memory by
04 cache memory04 cache memory
04 cache memorydilip kumar
457 views57 slides
7 (or so) deadly sins - PLMCE 2015 by
7 (or so) deadly sins - PLMCE 20157 (or so) deadly sins - PLMCE 2015
7 (or so) deadly sins - PLMCE 2015Martin Arrieta
357 views25 slides
Lecture 25 by
Lecture 25Lecture 25
Lecture 25Berkay TURAN
300 views39 slides
cache memory by
 cache memory cache memory
cache memoryNAHID HASAN
1.8K views39 slides

Similar to Windows 10 Nt Heap Exploitation (English version)(20)

Recon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_he by Liang Chen
Recon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_heRecon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_he
Recon2016 shooting the_osx_el_capitan_kernel_like_a_sniper_chen_he
Liang Chen253 views
Everything I Ever Learned About JVM Performance Tuning @Twitter by Attila Szegedi
Everything I Ever Learned About JVM Performance Tuning @TwitterEverything I Ever Learned About JVM Performance Tuning @Twitter
Everything I Ever Learned About JVM Performance Tuning @Twitter
Attila Szegedi110K views
7 (or so) deadly sins - PLMCE 2015 by Martin Arrieta
7 (or so) deadly sins - PLMCE 20157 (or so) deadly sins - PLMCE 2015
7 (or so) deadly sins - PLMCE 2015
Martin Arrieta357 views
cache memory by NAHID HASAN
 cache memory cache memory
cache memory
NAHID HASAN1.8K views
RecSplit Minimal Perfect Hashing by Thomas Mueller
RecSplit Minimal Perfect HashingRecSplit Minimal Perfect Hashing
RecSplit Minimal Perfect Hashing
Thomas Mueller1.5K views
A survey on Heap Exploitation by Alireza Karimi
A survey on Heap Exploitation A survey on Heap Exploitation
A survey on Heap Exploitation
Alireza Karimi73 views
Dynamic Memory Allocation(DMA) by Kamal Acharya
Dynamic Memory Allocation(DMA)Dynamic Memory Allocation(DMA)
Dynamic Memory Allocation(DMA)
Kamal Acharya3.5K views
Linux Kernel Booting Process (2) - For NLKB by shimosawa
Linux Kernel Booting Process (2) - For NLKBLinux Kernel Booting Process (2) - For NLKB
Linux Kernel Booting Process (2) - For NLKB
shimosawa8.3K views
Computer organization memory hierarchy by AJAL A J
Computer organization memory hierarchyComputer organization memory hierarchy
Computer organization memory hierarchy
AJAL A J6.8K views
Computer System Architecture Lecture Note 8.1 primary Memory by Budditha Hettige
Computer System Architecture Lecture Note 8.1 primary MemoryComputer System Architecture Lecture Note 8.1 primary Memory
Computer System Architecture Lecture Note 8.1 primary Memory
Budditha Hettige489 views
Webinar: Understanding Storage for Performance and Data Safety by MongoDB
Webinar: Understanding Storage for Performance and Data SafetyWebinar: Understanding Storage for Performance and Data Safety
Webinar: Understanding Storage for Performance and Data Safety
MongoDB1.2K views
.NET Memory Primer by Martin Kulov
.NET Memory Primer.NET Memory Primer
.NET Memory Primer
Martin Kulov1.6K views
Cache aware hybrid sorter by Manchor Ko
Cache aware hybrid sorterCache aware hybrid sorter
Cache aware hybrid sorter
Manchor Ko1.1K views
D2 t2 steven seeley - ghost in the windows 7 allocator by _mr_me
D2 t2   steven seeley - ghost in the windows 7 allocatorD2 t2   steven seeley - ghost in the windows 7 allocator
D2 t2 steven seeley - ghost in the windows 7 allocator
_mr_me1K views

More from Angel Boy

MacOS memory allocator (libmalloc) Exploitation - Chinese Version by
MacOS memory allocator (libmalloc) Exploitation - Chinese VersionMacOS memory allocator (libmalloc) Exploitation - Chinese Version
MacOS memory allocator (libmalloc) Exploitation - Chinese VersionAngel Boy
4.5K views115 slides
Linux Binary Exploitation - Return-oritend Programing by
Linux Binary Exploitation - Return-oritend ProgramingLinux Binary Exploitation - Return-oritend Programing
Linux Binary Exploitation - Return-oritend ProgramingAngel Boy
2.6K views91 slides
Linux Binary Exploitation - Stack buffer overflow by
Linux Binary Exploitation - Stack buffer overflowLinux Binary Exploitation - Stack buffer overflow
Linux Binary Exploitation - Stack buffer overflowAngel Boy
2.6K views92 slides
Binary exploitation - AIS3 by
Binary exploitation - AIS3Binary exploitation - AIS3
Binary exploitation - AIS3Angel Boy
7.3K views235 slides
Advanced heap exploitaion by
Advanced heap exploitaionAdvanced heap exploitaion
Advanced heap exploitaionAngel Boy
27.1K views55 slides
Heap exploitation by
Heap exploitationHeap exploitation
Heap exploitationAngel Boy
35.2K views100 slides

More from Angel Boy(9)

MacOS memory allocator (libmalloc) Exploitation - Chinese Version by Angel Boy
MacOS memory allocator (libmalloc) Exploitation - Chinese VersionMacOS memory allocator (libmalloc) Exploitation - Chinese Version
MacOS memory allocator (libmalloc) Exploitation - Chinese Version
Angel Boy4.5K views
Linux Binary Exploitation - Return-oritend Programing by Angel Boy
Linux Binary Exploitation - Return-oritend ProgramingLinux Binary Exploitation - Return-oritend Programing
Linux Binary Exploitation - Return-oritend Programing
Angel Boy2.6K views
Linux Binary Exploitation - Stack buffer overflow by Angel Boy
Linux Binary Exploitation - Stack buffer overflowLinux Binary Exploitation - Stack buffer overflow
Linux Binary Exploitation - Stack buffer overflow
Angel Boy2.6K views
Binary exploitation - AIS3 by Angel Boy
Binary exploitation - AIS3Binary exploitation - AIS3
Binary exploitation - AIS3
Angel Boy7.3K views
Advanced heap exploitaion by Angel Boy
Advanced heap exploitaionAdvanced heap exploitaion
Advanced heap exploitaion
Angel Boy27.1K views
Heap exploitation by Angel Boy
Heap exploitationHeap exploitation
Heap exploitation
Angel Boy35.2K views
Execution by Angel Boy
ExecutionExecution
Execution
Angel Boy25.6K views
Sigreturn Oriented Programming by Angel Boy
Sigreturn Oriented ProgrammingSigreturn Oriented Programming
Sigreturn Oriented Programming
Angel Boy26.4K views
Return to dlresolve by Angel Boy
Return to dlresolveReturn to dlresolve
Return to dlresolve
Angel Boy17.8K views

Recently uploaded

ChatGPT and AI for Web Developers by
ChatGPT and AI for Web DevelopersChatGPT and AI for Web Developers
ChatGPT and AI for Web DevelopersMaximiliano Firtman
181 views82 slides
Perth MeetUp November 2023 by
Perth MeetUp November 2023 Perth MeetUp November 2023
Perth MeetUp November 2023 Michael Price
15 views44 slides
1st parposal presentation.pptx by
1st parposal presentation.pptx1st parposal presentation.pptx
1st parposal presentation.pptxi238212
9 views3 slides
The Research Portal of Catalonia: Growing more (information) & more (services) by
The Research Portal of Catalonia: Growing more (information) & more (services)The Research Portal of Catalonia: Growing more (information) & more (services)
The Research Portal of Catalonia: Growing more (information) & more (services)CSUC - Consorci de Serveis Universitaris de Catalunya
73 views25 slides
PharoJS - Zürich Smalltalk Group Meetup November 2023 by
PharoJS - Zürich Smalltalk Group Meetup November 2023PharoJS - Zürich Smalltalk Group Meetup November 2023
PharoJS - Zürich Smalltalk Group Meetup November 2023Noury Bouraqadi
120 views17 slides

Recently uploaded(20)

Perth MeetUp November 2023 by Michael Price
Perth MeetUp November 2023 Perth MeetUp November 2023
Perth MeetUp November 2023
Michael Price15 views
1st parposal presentation.pptx by i238212
1st parposal presentation.pptx1st parposal presentation.pptx
1st parposal presentation.pptx
i2382129 views
PharoJS - Zürich Smalltalk Group Meetup November 2023 by Noury Bouraqadi
PharoJS - Zürich Smalltalk Group Meetup November 2023PharoJS - Zürich Smalltalk Group Meetup November 2023
PharoJS - Zürich Smalltalk Group Meetup November 2023
Noury Bouraqadi120 views
Unit 1_Lecture 2_Physical Design of IoT.pdf by StephenTec
Unit 1_Lecture 2_Physical Design of IoT.pdfUnit 1_Lecture 2_Physical Design of IoT.pdf
Unit 1_Lecture 2_Physical Design of IoT.pdf
StephenTec11 views
Lilypad @ Labweek, Istanbul, 2023.pdf by Ally339821
Lilypad @ Labweek, Istanbul, 2023.pdfLilypad @ Labweek, Istanbul, 2023.pdf
Lilypad @ Labweek, Istanbul, 2023.pdf
Ally3398219 views
Data-centric AI and the convergence of data and model engineering: opportunit... by Paolo Missier
Data-centric AI and the convergence of data and model engineering:opportunit...Data-centric AI and the convergence of data and model engineering:opportunit...
Data-centric AI and the convergence of data and model engineering: opportunit...
Paolo Missier34 views
Empathic Computing: Delivering the Potential of the Metaverse by Mark Billinghurst
Empathic Computing: Delivering  the Potential of the MetaverseEmpathic Computing: Delivering  the Potential of the Metaverse
Empathic Computing: Delivering the Potential of the Metaverse
Mark Billinghurst470 views
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by Bernd Ruecker
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
Bernd Ruecker26 views
Piloting & Scaling Successfully With Microsoft Viva by Richard Harbridge
Piloting & Scaling Successfully With Microsoft VivaPiloting & Scaling Successfully With Microsoft Viva
Piloting & Scaling Successfully With Microsoft Viva
AMAZON PRODUCT RESEARCH.pdf by JerikkLaureta
AMAZON PRODUCT RESEARCH.pdfAMAZON PRODUCT RESEARCH.pdf
AMAZON PRODUCT RESEARCH.pdf
JerikkLaureta15 views
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors by sugiuralab
TouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective SensorsTouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective Sensors
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors
sugiuralab15 views
Spesifikasi Lengkap ASUS Vivobook Go 14 by Dot Semarang
Spesifikasi Lengkap ASUS Vivobook Go 14Spesifikasi Lengkap ASUS Vivobook Go 14
Spesifikasi Lengkap ASUS Vivobook Go 14
Dot Semarang35 views

Windows 10 Nt Heap Exploitation (English version)