{"id":11044,"date":"2016-07-05T23:59:38","date_gmt":"2016-07-05T21:59:38","guid":{"rendered":"https:\/\/www.corelan.be\/?p=11044"},"modified":"2016-07-05T23:59:38","modified_gmt":"2016-07-05T21:59:38","slug":"windows-10-x86wow64-userland-heap","status":"publish","type":"post","link":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/","title":{"rendered":"Windows 10 x86\/wow64 Userland heap"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>Hi all,<\/p>\n<p>Over the course of the past few weeks ago, I received a number of &quot;emergency&quot; calls from some relatives, asking me to look at their computer because &quot;things were broken&quot;, &quot;things looked different&quot; and &quot;I think my computer got hacked&quot;.&#160; I quickly realized that their computers got upgraded to Windows 10.<\/p>\n<p>We could have a lengthy discussion about the strategy to force upgrades onto people, but in any case it is clear that Windows 10 is gaining market share.&#160; This also means that it has become a Windows version that is relevant enough to investigate.<\/p>\n<p>In this post, I have gathered some notes on how the userland heap manager behaves for 32bit processes in Windows 10.&#160; The main focus of my investigation is to document the similarities and differences with Windows 7, and hopefully present some ideas on how to manipulate the heap to increase predictability of its behavior.&#160;&#160; More specifically, aside from documenting behavior, I am particularly interested in getting answers to the following questions:<\/p>\n<ol>\n<li><font color=\"#ffffff\">How does the back-end allocator behave?<\/font><\/li>\n<li><font color=\"#ffffff\">What does it take to activate the LFH?<\/font><\/li>\n<li><font color=\"#ffffff\">What are the differences in terms of LFH behavior between Win7 and Win10, if any?<\/font><\/li>\n<li><font color=\"#ffffff\">What options do we have to create a specific heap layout that involves certain objects to be adjacent in memory?&#160; (objects of the same size, objects of different sizes)<\/font><\/li>\n<li><font color=\"#ffffff\">Can we perform a &quot;reliable&quot; and precise heap spray?<\/font><\/li>\n<\/ol>\n<p>As I am a terrible reverse engineer, it's worth noting that the notes below are merely a transcript of my observations, and not backed by disassembling\/decompiling\/reverse engineering ntdll.dll.&#160; Furthermore, as the number of tests were limited (far below what would be needed to provide some level of statistical certainty), I am not 100% sure that my descriptions can be considered a true representation of reality.&#160;&#160; In any case, I hope the notes will inspire people to do more tests, to perform reverse engineering on some of the heap management related code, and share more details on how things were implemented.<\/p>\n<p>This post assumes that you already have experience with the Windows 7 heap and its front-end and back-end allocators, and that you understand the output of various !heap commands.&#160;&#160; <\/p>\n<p>In my test applications, I'll be using the default process heap.&#160; It would be fair to assume that the notes below apply to all windows heaps and applications that rely on the windows heap management system.<\/p>\n<p>Throughout this post, I will use the following terminology:<\/p>\n<ul>\n<li><font color=\"#ffffff\">chunk: a contiguous piece of memory<\/font><\/li>\n<li><font color=\"#ffffff\">block: size unit, referring to 8 bytes of memory.&#160; (Don't be confused when you see the word &quot;block&quot; in WinDBG output. WinDBG uses the term &quot;block&quot; to reference a chunk.&#160; I am using different terminology.<\/font><\/li>\n<li><font color=\"#ffffff\">virtualallocdblock: a chunk that was allocated through RtlAllocateHeap, but is larger than the VirtualMemoryTHreshold (and thus is not stored inside a segment, but rather as a separate chunk in memory), and managed through the VirtualAllocdBlocks list. (offset 0x9c in the heap header)<\/font><\/li>\n<li><font color=\"#ffffff\">segment: the heap management unit, managed by a heap, used to allocate &amp; manage chunks.&#160; The segment list is managed inside the heap header (offset 0xa4)<\/font><\/li>\n<li><font color=\"#ffffff\">SubSegment: the LFH management unit used to manage LFH chunks<\/font><\/li>\n<\/ul>\n<h3>Test environment<\/h3>\n<p>My test environment consists of the following components:<\/p>\n<ul>\n<li><font color=\"#ffffff\">Windows 10 Enterprise x64, fully patched&#160; (running as a virtual machine inside VirtualBox) with 2 CPUs and 1.8Gb of RAM<\/font><\/li>\n<li><font color=\"#ffffff\">Visual Studio Express 2015 for desktop : <\/font><a href=\"https:\/\/go.microsoft.com\/fwlink\/?LinkId=691984&amp;clcid=0x409\"><font color=\"#ffffff\">https:\/\/go.microsoft.com\/fwlink\/?LinkId=691984&amp;clcid=0x409<\/font><\/a><\/li>\n<li><font color=\"#ffffff\">WinDBG (for Windows 10) : <\/font><a href=\"https:\/\/go.microsoft.com\/fwlink\/p\/?LinkId=536682\"><font color=\"#ffffff\">https:\/\/go.microsoft.com\/fwlink\/p\/?LinkId=536682<\/font><\/a><font color=\"#ffffff\">.&#160; (Make sure to run a recent version of WinDBG to make sure all heap related structures are properly parsed and represented)<\/font><\/li>\n<\/ul>\n<p>I have set up Symbol support for WinDBG by creating a system environment variable:<\/p>\n<ul>\n<li><font color=\"#ffffff\"><strong>Variable<\/strong>:&#160; _NT_SYMBOL_PATH<\/font><\/li>\n<li><font color=\"#ffffff\"><strong>Value<\/strong>: srv*c:\\symbols*http:\/\/msdl.microsoft.com\/download\/symbols<\/font><\/li>\n<\/ul>\n<p>The source code (Visual Studio C++ projects) for all test cases used in this post can be found here:&#160; <a href=\"https:\/\/github.com\/corelan\/win10_heap\">https:\/\/github.com\/corelan\/win10_heap<\/a>&#160;<\/p>\n<h3>The Heap<\/h3>\n<p>Similar to previous Windows versions, the Windows 10 heap sits at an ASLR-influenced (&quot;random&quot;) address and starts with a header. As the base address of the heap management unit sits at a non-static address, you'll see different heap base addresses throughout this post.&#160; In order to avoid confusion, I'll use the term &quot;address of default process heap&quot; to refer to this base address.&#160; Similarly, any address you'll see in the post will be different on your machine.&#160; <\/p>\n<p>Dumping the header contents of a heap, we can oberve the following fields:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; dt _HEAP 00a40000\n<\/p><p>ntdll!_HEAP <br \/>+0x000 Segment : _HEAP_SEGMENT <br \/>+0x000 Entry : _HEAP_ENTRY <br \/>+0x008 SegmentSignature : 0xffeeffee <br \/>+0x00c SegmentFlags : 2 <br \/>+0x010 SegmentListEntry : _LIST_ENTRY [ 0xa400a4 - 0xa400a4 ] <br \/>+0x018 Heap : 0x00a40000 _HEAP <br \/>+0x01c BaseAddress : 0x00a40000 Void <br \/>+0x020 NumberOfPages : 0xff <br \/>+0x024 FirstEntry : 0x00a40498 _HEAP_ENTRY <br \/>+0x028 LastValidEntry : 0x00b3f000 _HEAP_ENTRY <br \/>+0x02c NumberOfUnCommittedPages : 0xe9 <br \/>+0x030 NumberOfUnCommittedRanges : 1 <br \/>+0x034 SegmentAllocatorBackTraceIndex : 0 <br \/>+0x036 Reserved : 0 <br \/>+0x038 UCRSegmentList : _LIST_ENTRY [ 0xa55ff0 - 0xa55ff0 ] <br \/>+0x040 Flags : 2 <br \/>+0x044 ForceFlags : 0 <br \/>+0x048 CompatibilityFlags : 0 <br \/>+0x04c EncodeFlagMask : 0x100000 <br \/>+0x050 Encoding : _HEAP_ENTRY <br \/>+0x058 Interceptor : 0 <br \/>+0x05c VirtualMemoryThreshold : 0xfe00 <br \/>+0x060 Signature : 0xeeffeeff <br \/>+0x064 SegmentReserve : 0x100000 <br \/>+0x068 SegmentCommit : 0x2000 <br \/>+0x06c DeCommitFreeBlockThreshold : 0x800 <br \/>+0x070 DeCommitTotalFreeThreshold : 0x2000 <br \/>+0x074 TotalFreeSize : 0x462 <br \/>+0x078 MaximumAllocationSize : 0x7ffdefff <br \/>+0x07c ProcessHeapsListIndex : 1 <br \/>+0x07e HeaderValidateLength : 0x248 <br \/>+0x080 HeaderValidateCopy : (null) <br \/>+0x084 NextAvailableTagIndex : 0 <br \/>+0x086 MaximumTagIndex : 0 <br \/>+0x088 TagEntries : (null) <br \/>+0x08c UCRList : _LIST_ENTRY [ 0xa55fe8 - 0xa55fe8 ] <br \/>+0x094 AlignRound : 0xf <br \/>+0x098 AlignMask : 0xfffffff8 <br \/>+0x09c VirtualAllocdBlocks : _LIST_ENTRY [ 0xa4009c - 0xa4009c ] <br \/>+0x0a4 SegmentList : _LIST_ENTRY [ 0xa40010 - 0xa40010 ] <br \/>+0x0ac AllocatorBackTraceIndex : 0 <br \/>+0x0b0 NonDedicatedListLength : 0 <br \/>+0x0b4 BlocksIndex : 0x00a40260 Void <br \/>+0x0b8 UCRIndex : (null) <br \/>+0x0bc PseudoTagEntries : (null) <br \/>+0x0c0 FreeLists : _LIST_ENTRY [ 0xa4cd80 - 0xa53e70 ] <br \/>+0x0c8 LockVariable : 0x00a40248 _HEAP_LOCK <br \/>+0x0cc CommitRoutine : 0x4807219e long +4807219e <br \/>+0x0d0 FrontEndHeap : 0x003f0000 Void <br \/>+0x0d4 FrontHeapLockCount : 0 <br \/>+0x0d6 FrontEndHeapType : 0x2 '' <br \/>+0x0d7 RequestedFrontEndHeapType : 0x2 '' <br \/>+0x0d8 FrontEndHeapUsageData : 0x00a43fe8 -&gt; 0 <br \/>+0x0dc FrontEndHeapMaximumIndex : 0x802 <br \/>+0x0de FrontEndHeapStatusBitmap : [257] &quot;???&quot; <br \/>+0x1e0 Counters : _HEAP_COUNTERS <br \/>+0x23c TuningParameters : _HEAP_TUNING_PARAMETERS<\/p><\/pre>\n<p>The header starts with information about the segments associated with this heap.<\/p>\n<p>Offset 0x4c (EncodeFlagMask) and 0x50 (Encoding) are used to store information about the chunk header encoding in the heap (= same offsets as in Windows 7).&#160;&#160; The actual key used to encode and decode the chunk header fields (XOR) is stored at offset 0x50.&#160;&#160; Fortunately the WinDBG !heap extension will perform all decoding for us.&#160;&#160; As you can imagine, this key is 1\/ random for each process and 2\/ different for each heap in the process, which means it is (still) quite effective at preventing heap header attacks.<\/p>\n<p>Also, similar to Windows 7, the VirtualMemoryThreshold field (offset 0x5c) contains value 0xfe00.&#160; As this value denotes the number of blocks, we need to multiply the value with 8 to get the actual number of bytes. (0x7F000 bytes).&#160; In other words, we can still trigger VirtualAllocdBlocks by causing a regular (HeapAlloc) allocation of a size that is larger than this value.&#160; Some of the heap spray techniques documented here and <a href=\"https:\/\/www.corelan.be\/index.php\/2013\/02\/19\/deps-precise-heap-spray-on-firefox-and-ie10\/\">here<\/a> were based on triggering VirtualAllocBlock chunks.&#160; We'll see if the current implementation still allows for a precise heap spray.<\/p>\n<p>Offset 0x0d6 (FrontEndHeapType) indicates what front-end allocator is being used.&#160; Value 0x2 refers to LFH.&#160;&#160; The address of the FrontEndHeap &quot;master&quot; header structure can be found at the address referenced at offset 0xd0 (FrontEndHeap).&#160; In the example above, the LFH header is stored at 0x003f0000 and contains the following information:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; dt _LFH_HEAP 0x003f0000 <\/p><p>ntdll!_LFH_HEAP \n+0x000 Lock : _RTL_SRWLOCK \n+0x004 SubSegmentZones : _LIST_ENTRY [ 0xa48910 - 0xa48910 ] \n+0x00c Heap : 0x00a40000 Void \n+0x010 NextSegmentInfoArrayAddress : 0x003f0a08 Void \n+0x014 FirstUncommittedAddress : 0x003f1000 Void \n+0x018 ReservedAddressLimit : 0x003f8000 Void \n+0x01c SegmentCreate : 7 \n+0x020 SegmentDelete : 1 \n+0x024 MinimumCacheDepth : 0 \n+0x028 CacheShiftThreshold : 0 \n+0x02c SizeInCache : 0 \n+0x030 RunInfo : _HEAP_BUCKET_RUN_INFO \n+0x038 UserBlockCache : [12] _USER_MEMORY_CACHE_ENTRY \n+0x1b8 MemoryPolicies : _HEAP_LFH_MEM_POLICIES \n+0x1bc Buckets : [129] _HEAP_BUCKET \n+0x3c0 SegmentInfoArrays : [129] (null) \n+0x5c4 AffinitizedInfoArrays : [129] (null) \n+0x7c8 SegmentAllocator : (null) \n+0x7d0 LocalData : [1] _HEAP_LOCAL_DATA<\/p><\/pre>\n<p>We can see references to various LFH terms, including &quot;Bucket&quot;, &quot;SubSegment&quot; and &quot;Heap local data&quot;.<\/p>\n<p>Based on some quick tests, it looks like the LFH_HEAP header is (usually\/always?) stored within the first segment of the heap on Windows 7, but on Windows 10 it seems to be stored outside of the memory range used by the first segment.<\/p>\n<p>Putting things in a graphical (but very high-level and abstract) manner, the heap pretty much consists of the following building blocks:<\/p>\n<p><a class=\"thickbox\" href=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1.png\"><img loading=\"lazy\" decoding=\"async\" title=\"heap1\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 7px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"heap1\" src=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1_thumb.png\" width=\"462\" height=\"327\" \/><\/a><\/p>\n<h3>The back-end allocator<\/h3>\n<h4>BEA_Alloc1<\/h4>\n<p>On Windows 7, the back-end allocator (BEA) is the default\/active mechanism used to manage freed chunks.&#160; Based on my observations, this is still the case on Windows 10. It uses the chunks available inside the segment(s) and starts empty.&#160; As soon as a chunk gets freed, it will &quot;remember&quot; these free chunks in some kind of list.&#160; The free chunks are organized per size, and the mechanism uses a table to do so. Each entry in the table represents a size (increment of 8 bytes), and index 0 is used to manage chunks that are larger than the chunk size managed by index 127.<\/p>\n<p>The FreeList table is now referenced at offset 0xc0 from the heap base.&#160; I didn't check in detail, but I am assuming that the table stil consists of 128 elements, and that each entry is basically a Flink\/Blink to the double linked list of free chunks managed in the table entry, or null pointers (to indicate there are no free chunks of the size that is managed by the corresponding table entry).&#160; Again, I didn't verify in detail, as I'm more interested in how it behaves at this time.<\/p>\n<p>In order to evaluate its behavior on Windows 10, we'll run some basic tests using a couple of example applications.&#160; You can find the sourcecode and binary for this first test in the &quot;BEA_Alloc1&quot; folder in the github repository.<\/p>\n<p>This first test application starts by allocating 2 chunks of 0x300 bytes each.&#160; This should not be a common object size in my simple test application, and should be large enough to<\/p>\n<ul>\n<li><font color=\"#ffffff\">avoid that the back-end allocator already has chunks of that size on its freelist<\/font><\/li>\n<li><font color=\"#ffffff\">avoid that the back-end allocator already has chunks that are bigger that this size on its freelist<\/font><\/li>\n<li><font color=\"#ffffff\">avoid that the LFF is already active for the bucket that contains chunks of this size<\/font><\/li>\n<\/ul>\n<div>(I don't really know if these 'conditions' will be met, but we'll find out)<\/div>\n<p>In any case, the goal of these 2 allocations is to check where these 2 chunks will be allocated from (i.e. from a normal segment) and if they are placed next to each other.&#160;&#160; If that is the case, and if we free both chunks, we'll check if they get coalesced (merged together) by the BEA and managed in its free list.&#160; Finally, if we then ask for a new allocation, let's see if the BEA is going to split the chunk and use it to satisfy new requests.<\/p>\n<p>Let's go ahead &amp; compile + run the binary.&#160; The application will first print the address of the default process heap and will then wait for you to press return.<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10\\BEA_Alloc1\\Release&gt;BEA_Alloc1.exe \n<\/p><p>Default process heap found at 0x01550000 <br \/>Press a key to start...<\/p><\/pre>\n<p>Attach WinDBG and check the state of the default process heap allocations at this point with !heap -p -h &lt;address of default process heap&gt;. <\/p>\n<p>As I am only interested in the &quot;free&quot; chunks at this point, I have removed all lines from the output that correspond with a &quot;busy&quot; chunk and\/or are part of a LFH subsegment for a different bucket size.&#160; (in case you're wondering how to recognize those: simply look for lines that are preceded by an asterisk (*), indicating a large busy\/internal chunk, and followed by a list a smaller chunks of similar sizes within the address range of this larger busy\/internal chunk.&#160;&#160; This larger one is the subsegment, the smaller ones are the LFH managed chunks inside that subsegment).<\/p>\n<p>In other words, I'm only listing the chunks that are managed by the BEA and could potentially be used to satisfy the allocation requests caused by my test application.<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; !heap -p -h 0x01550000 _HEAP @ 1550000 \n_LFH_HEAP @ f80000 \n_HEAP_SEGMENT @ 1550000 \nCommittedRange @ 1550498 \nHEAP_ENTRY Size Prev Flags UserPtr UserSize - state\n<\/p><p>01551db0 0005 0045 [00] 01551db8 00020 - (free)<\/p><p>01552b00 0021 0012 [00] 01552b08 00100 - (free)\n01552cb0 0015 0015 [00] 01552cb8 000a0 - (free) \n015573a8 0008 000b [00] 015573b0 00038 - (free) \n01557578 0002 0008 [00] 01557580 00008 - (free) \n01559080 0003 0041 [00] 01559088 00010 - (free) \n01559098 0003 0003 [00] 015590a0 00010 - (free) \n015590e0 0003 0003 [00] 015590e8 00010 - (free) \n01559110 0003 0003 [00] 01559118 00010 - (free) \n01559128 0003 0003 [00] 01559130 00010 - (free) \n01559140 0003 0003 [00] 01559148 00010 - (free) \n01559158 0003 0003 [00] 01559160 00010 - (free) \n01559170 0003 0003 [00] 01559178 00010 - (free) \n01559188 0003 0003 [00] 01559190 00010 - (free) \n015591a0 0003 0003 [00] 015591a8 00010 - (free) \n015591d0 0003 0003 [00] 015591d8 00010 - (free) \n015591e8 0003 0003 [00] 015591f0 00010 - (free) \n01559200 0003 0003 [00] 01559208 00010 - (free) \n01559218 0003 0003 [00] 01559220 00010 - (free) \n01559230 0003 0003 [00] 01559238 00010 - (free) \n0155d9b0 0018 000a [00] 0155d9b8 000b8 - (free) \n0155dcc8 0012 000a [00] 0155dcd0 00088 - (free) \n0155e538 002e 0021 [00] 0155e540 00168 - (free) \n0155e6d0 0004 0081 [00] 0155e6d8 00018 - (free) \n0155e6f0 0004 0004 [00] 0155e6f8 00018 - (free) \n0155e710 0004 0004 [00] 0155e718 00018 - (free) \n0155e730 0004 0004 [00] 0155e738 00018 - (free) \n0155e750 0004 0004 [00] 0155e758 00018 - (free) \n0155e770 0004 0004 [00] 0155e778 00018 - (free) \n0155e790 0004 0004 [00] 0155e798 00018 - (free) \n0155e7b0 0004 0004 [00] 0155e7b8 00018 - (free) \n0155e7d0 0004 0004 [00] 0155e7d8 00018 - (free) \n0155e7f0 0004 0004 [00] 0155e7f8 00018 - (free) \n0155e810 0004 0004 [00] 0155e818 00018 - (free) \n0155e830 0004 0004 [00] 0155e838 00018 - (free) \n0155e890 0004 0004 [00] 0155e898 00018 - (free) \n0155e990 0004 0004 [00] 0155e998 00018 - (free) \n0155e9d0 0004 0004 [00] 0155e9d8 00018 - (free) \n0155e9f0 0004 0004 [00] 0155e9f8 00018 - (free) \n0155ea10 0004 0004 [00] 0155ea18 00018 - (free) \n0155ea30 0004 0004 [00] 0155ea38 00018 - (free) \n0155ea70 0004 0004 [00] 0155ea78 00018 - (free) \n01561438 0175 0201 [00] 01561440 00ba0 - (free)<\/p><\/pre>\n<p>As you can see, there are no free chunks of exactly 0x300 bytes, however the last line in the output shows a free chunk of 0xba0 bytes (01561440 - 01561FE0). <\/p>\n<p>This is quite normal, as this is the remaining space in the segment that has not been allocated yet. It shows up as a free chunk (because that's exactly what it is) and will be split to satisfy new allocation requests ( = that's pretty much how the BEA works when it has to use a larger chunk to satisfy an allocation request).&#160; <\/p>\n<p>Since there are no free chunks of 0x300 bytes, a larger free chunk should be split (providing that the one in the list above is not being used by LFH... but as the flag is set to &quot;free&quot; and as it is not part of a larger subsegment, it shouldn't be related with LFH at all.&#160; After all, a subsegment typically shows up as a larger chunk that is marked as &quot;busy&quot; and &quot;internal&quot;). <\/p>\n<p>Anyway, let's verify to be sure:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; !heap -p -a 01561438 <\/p><p>address 01561438 found in \n_HEAP @ 1550000 \nHEAP_ENTRY <\/p><p>    Size Prev Flags     UserPtr  UserSize - state \n01561438 0175 0000 [00] 01561440 00ba0 - (free)\n<\/p><p>0:003&gt; !heap -x 01561438 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n01561438 01561440 01550000 01550000 ba8 1008 0 free<\/p><\/pre>\n<p>The &quot;flags&quot; indicate that this is not an LFH managed chunk.&#160; (Otherwise, the output would have mentioned the word &quot;LFH&quot; as well)<\/p>\n<p>Continue to run the application &amp; see what happens:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>Allocated chunk of 0x300 bytes at 0x01561440\n<\/p><p>Allocated chunk of 0x300 bytes at 0x01561748 <br \/>Press return to continue<\/p><\/pre>\n<p>Based on the addresses returned by HeapAlloc, it looks like the final free chunk of 0xba0 bytes (at 0x1561440) was indeed split into pieces:<\/p>\n<ul>\n<li><font color=\"#ffffff\">a chunk of 0x300 bytes, taken from the start of the larger free chunk, allocated at 0x01561440. The larger free chunk is now smaller, but still big enough to satisfy another request.&#160; <\/font><\/li>\n<li><font color=\"#ffffff\">another piece of 0x300 bytes bytes, allocated at 0x01561748, taken from the (new) start of the larger free chunk.<\/font><\/li>\n<\/ul>\n<p>Both allocations sit next to each other, because allocations are taken from the start of a free chunk when splitting.&#160; As both allocations are taken from the same larger chunk, it is expected from them to sit together. What is left of the original 0xba0 byte chunk is 0x590 bytes (as expected, showing up as a free chunk which starts at 01561a50 and ends at 01561FE0)<\/p>\n<p>WinDBG: !heap -p -h &lt;address of default process heap&gt; (output limited to the 3 chunks that are relevant to this exercise: the 2 &quot;new&quot; allocations, and the remaining space)<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>01561438 0061 0201 [00] 01561440 00300 - (busy) <\/p><p>01561740 0061 0061 [00] 01561748 00300 - (busy) \n<\/p><p>01561a48 00b3 0061 [00] 01561a50 00590 - (free)<\/p><\/pre>\n<p>Great, but we have not been really using the FreeList mechanisms of the BEA at this point.&#160;&#160; All we have been doing is allocate chunks from within a normal segment, consuming the free space that was there all the time.&#160;&#160; To trigger the BEA FreeList mechanism and see how it behaves, we'll have to &quot;free&quot; some chunks ourselves first.<\/p>\n<h4>BEA_Alloc2<\/h4>\n<p>In this second example, we'll create a series of allocations of 0x300 bytes.&#160;&#160; We'll free the last one and then cause 2 allocations of 0x100 bytes.&#160; <\/p>\n<p>The purpose of the exercise is to check where these 2 allocations will be placed.&#160; <\/p>\n<p>As we intend to evaluate the BEA mechanism, we have to avoid that the LFH gets triggered.&#160; We know that the heap manager in Windows 7 will trigger the LFH when it sees 18 consecutive allocations of a size in the same bucket (i.e. the next request will be allocated from within a LFH managed subsegment). <\/p>\n<p>For that reason, we'll only cause 10 allocations of 0x300 bytes, hopefully avoiding that the LFH will be used.<\/p>\n<p>After causing the 10 allocations, let's examine the last one and see if LFH is on or off.<\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10\\BEA_Alloc2\\Release&gt;BEA_Alloc2.exe\nDefault process heap found at 0x009B0000\nPress a key to start...\nAllocated chunk of 0x300 bytes at 0x009BF1D0\nAllocated chunk of 0x300 bytes at 0x009BF4D8\nAllocated chunk of 0x300 bytes at 0x009BF7E0\nAllocated chunk of 0x300 bytes at 0x009BFAE8\nAllocated chunk of 0x300 bytes at 0x009BFDF0\nAllocated chunk of 0x300 bytes at 0x009C00F8\nAllocated chunk of 0x300 bytes at 0x009C0400\nAllocated chunk of 0x300 bytes at 0x009C0708\nAllocated chunk of 0x300 bytes at 0x009C0A10\nAllocated chunk of 0x300 bytes at 0x009C0D18<br \/>\nPress return to continue<\/p><\/pre>\n<p>WinDBG:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; !heap -x 0x009C0D18\n<\/p><p>Entry&#160;&#160;&#160;&#160; User&#160;&#160;&#160;&#160;&#160; Heap&#160;&#160;&#160;&#160;&#160; Segment&#160;&#160;&#160;&#160;&#160;&#160; Size&#160; PrevSize&#160; Unused&#160;&#160;&#160; Flags\n<\/p><p>-----------------------------------------------------------------------------\n<\/p><p>009c0d10&#160; 009c0d18&#160; 009b0000&#160; 009b0000&#160;&#160;&#160;&#160;&#160;&#160; 308&#160;&#160;&#160;&#160;&#160;&#160; 308&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 8&#160; busy<\/p><\/pre>\n<div><\/div>\n<div>So far so good, no sign of LFH at this point.&#160;&#160; Next, the application will free this last chunk:<\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>Free chunk at 0x009C0D18\nPress return to continue\n<\/div><\/pre>\n<div><\/div>\n<div>WinDBG:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>0:003&gt; !heap -x 0x009C0D18  <div>Entry&#160;&#160;&#160;&#160; User&#160;&#160;&#160;&#160;&#160; Heap&#160;&#160;&#160;&#160;&#160; Segment&#160;&#160;&#160;&#160;&#160;&#160; Size&#160; PrevSize&#160; Unused&#160;&#160;&#160; Flags\n<\/div><div>-----------------------------------------------------------------------------\n<\/div><div>009c0d10&#160; 009c0d18&#160; 009b0000&#160; 009b0000&#160;&#160;&#160;&#160;&#160; 12d0&#160;&#160;&#160;&#160;&#160;&#160; 308&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 0&#160; free <\/div><\/div><\/pre>\n<p>Before running the rest of the application, let's look at the current state of the heap, looking for &quot;free&quot; chunks of 0x300 bytes or larger.&#160; The output below only contains the relevant lines:<\/p>\n<p>WinDBG:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; !heap -p -h 0x009B0000\n<\/p><p>_HEAP @ 9b0000\n<\/p><p>_LFH_HEAP @ 610000\n<\/p><p>_HEAP_SEGMENT @ 9b0000\n<\/p><p>CommittedRange @ 9b0498\n<\/p><p>HEAP_ENTRY Size Prev Flags&#160;&#160;&#160; UserPtr UserSize - state\n<\/p><p>009c0d10 025a 0061&#160; [00]&#160;&#160; 009c0d18&#160;&#160;&#160; 012c8 - (free)<\/p><\/pre>\n<div>As we can see in the output, as the last chunk of 0x300 bytes was allocated right before the remaining free space in the segment, this now freed chunk got merged with the adjacent free space in the segment, and has now become a 0x12c8 byte free chunk. This larger free chunk starts at 009c0d10, which is also the start address of the 0x300 byte chunk that was freed.&#160;&#160; <\/div>\n<div><\/div>\n<div>Our test application will now cause 2 allocations of 0x100 bytes each. Sure enough, this is large enough to satisfy 2 requests for 0x100 bytes, but in order to predict what exactly will happen, we need to look at the heap state again first.<\/div>\n<div><\/div>\n<div>The output of !heap -p -h &lt;default process heap&gt; shows the following lines that refer to free chunks of 0x100 bytes or more:<\/div>\n<div><\/div>\n<div>WinDBG:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\n<div>0:003&gt; !heap -p -h 0x009B0000  <\/div><div>&#160;&#160;&#160; _HEAP @ 9b0000  <\/div><div>&#160;&#160;&#160;&#160;&#160; _LFH_HEAP @ 610000\n<\/div><div>&#160;&#160;&#160;&#160;&#160; _HEAP_SEGMENT @ 9b0000\n<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160; CommittedRange @ 9b0498  <\/div><div>&#160;&#160;&#160;&#160;&#160; HEAP_ENTRY Size Prev Flags&#160;&#160;&#160; UserPtr UserSize - state\n<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 009b2b00 0021 0012&#160; [00]&#160;&#160; 009b2b08&#160;&#160;&#160; 00100 - (free)\n<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 009bc330 0034 0089&#160; [00]&#160;&#160; 009bc338&#160;&#160;&#160; 00198 - (free)\n<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 009c0d10 025a 0061&#160; [00]&#160;&#160; 009c0d18&#160;&#160;&#160; 012c8 - (free)\n<\/div><\/div><\/pre>\n<div>Based on the output, we can see<\/div>\n<div>\n<ul>\n<li><font color=\"#ffffff\">A free chunk of exactly 0x100 bytes (entry starts at 009b2b00, userptr is 009b2b08)&#160; <\/font><\/li>\n<li><font color=\"#ffffff\">A free chunk of 0x198 bytes (entry starts at 009bc330, userptr is 009bc338) <\/font><\/li>\n<li><font color=\"#ffffff\">The remaining free space in the segment, at 009c0d10<\/font><\/li>\n<\/ul>\n<\/div>\n<div><\/div>\n<div>Let's see what logic is applied by the BEA to reuse those freed chunks:<\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>Allocated chunk of 0x100 bytes at 0x009B2B08\n<\/div><div>Allocated chunk of 0x100 bytes at 0x009BC338\n<\/div><div>Done...<\/div><\/pre>\n<div>This makes sense.&#160; The chunk that is exactly the size of the allocation request gets reused first.&#160; Next, the next one that is larger gets split.&#160; The remaining space near the end of the segment, which is now a combination of the original free space and the 0x300 byte chunk that was freed, does not get used.<\/div>\n<div><\/div>\n<div>The 2 chunks are not adjacent (despite the allocations happened right after each other).&#160; None of the 2 chunks were able to take memory space back from one the 0x300 byte chunk that was freed earlier. <\/div>\n<div><\/div>\n<div>The behavior is absolutely normal, but this means that we cannot simply use the BEA to take a previously-allocated-and-now-freed chunk back... at least not without doing some &quot;massaging&quot;.&#160; <\/div>\n<div>On the other hand, because the BEA does not keep chunks together based on buckets, and if we can improve control, we may be able to use a smaller or a larger allocation size to take a position back in memory that has been freed, regardless of the original size of that freed chunk. <\/div>\n<div><\/div>\n<div>Let's try to increase control over what happens, increasing our chances that we can take a freed chunk back.<\/div>\n<div><\/div>\n<div><\/div>\n<h4>BEA_Alloc3<\/h4>\n<div>As demonstrated in the previous exercise, the fact that the BEA is managing freed chunks means that, by default, we may not be able to predict where a new allocation will be placed relative to another chunk or in relation with taking the space of a freed chunk (which would be useful in a Use After Free scenario).&#160; <\/div>\n<div><\/div>\n<div>Let's start with the latter scenario first.&#160;&#160; What does it take to take a freed chunk back?<\/div>\n<div><\/div>\n<div>The answer is quite simple: it depends on what else is free.&#160;&#160; <\/div>\n<div>A possible approach to control what else is free, is to simply reduce what is free at the time the free happens that you would like to take back. The idea is to exhaust the freelist as much as possible... and to do that, we need to cause allocations.<\/div>\n<div><\/div>\n<div>Additionally, we may want to check that the freed chunk (the one we're trying to take back... we'll call this one the 'vulnerable' freed chunk) does not sit after an already freed chunk.&#160; This would cause both chunks to be merged, and subsequent allocation requests would start consuming the start of the new (bigger chunk).&#160; Depending on the size of the first part, it may be difficult to get perfect control over the contents.&#160; On the other hand, if you can control the size of that first freed chunk (which will eventually get merged with the 'vulnerable' freed chunk), it might actually allow you to improve control over what bytes exactly you will manage if you don't control all bytes of the new allocation.&#160; <\/div>\n<div><\/div>\n<div>Again, it all depends on the layout that you create, and your understanding of what is inside the free list at the time of the allocation that is supposed to take the place of the &quot;vulnerable&quot; freed chunk.<\/div>\n<div><\/div>\n<div>Anyway, let's look at an example.&#160; BEA_Alloc3 contains the following scenario: we'll free a 0x58 byte chunk, and the goal is to use a 0x58 byte allocation that will take its position back<\/div>\n<div><\/div>\n<div>Obviously we have to make sure that LFH is never activated (as we are playing with the BEA), and that we can avoid that the 0x58 byte chunk gets merged with an adjacent free chunk.&#160;&#160; This means that we could try to surround the 0x58 byte chunk by 2 allocations that we created as well, but won't allow to be freed.&#160;&#160; <\/div>\n<div><\/div>\n<div>In order for all 3 allocations to be adjacent, we have to make sure there is nothing on the free list already that will satisfy any of the 3 allocation requests.&#160; In the example application, I am using 10 allocations for both sizes, but of course in reality, you'll need to check how many allocations you need to truly remove all free chunks; while being careful about avoiding LFH at the same time.<\/div>\n<div><\/div>\n<div>As the size of the 1st and 3rd allocation (the ones before and after the 0x58 byte chunk) is not so important, we can choose a size that is not on the freelist yet.&#160; (Sizes are not important, because we don't have to take LFH bucket sizes into account. Again, we're playing with the BEA).&#160; Anyway, I'll use 0x100 byte chunk to surround the 0x58 chunk.<\/div>\n<div><\/div>\n<div>Run the application, and check the heap after causing a series of allocations for 0x58 and 0x100 bytes, to exhaust the freelist for those sizes.<\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\nC:\\Users\\corelan\\Desktop\\vc++\\win10\\BEA_Alloc3\\Release&gt;BEA_Alloc3.exe \n    <br \/>Default process heap found at 0x016C0000 <br \/>Press a key to start...\n<p>Allocated chunk of 0x58 bytes at 0x016C96D0     <br \/>Allocated chunk of 0x100 bytes at 0x016C2B08 <br \/>Allocated chunk of 0x58 bytes at 0x016CDF50 <br \/>Allocated chunk of 0x100 bytes at 0x016CD328 <br \/>Allocated chunk of 0x58 bytes at 0x016CD430 <br \/>Allocated chunk of 0x100 bytes at 0x016CFFF8 <br \/>Allocated chunk of 0x58 bytes at 0x016C2CB8 <br \/>Allocated chunk of 0x100 bytes at 0x016D0100 <br \/>Allocated chunk of 0x58 bytes at 0x016CDC18 <br \/>Allocated chunk of 0x100 bytes at 0x016D0208 <br \/>Allocated chunk of 0x58 bytes at 0x016CDC78 <br \/>Allocated chunk of 0x100 bytes at 0x016D0310 <br \/>Allocated chunk of 0x58 bytes at 0x016D0418 <br \/>Allocated chunk of 0x100 bytes at 0x016D0478 <br \/>Allocated chunk of 0x58 bytes at 0x016D0580 <br \/>Allocated chunk of 0x100 bytes at 0x016D05E0 <br \/>Allocated chunk of 0x58 bytes at 0x016D06E8 <br \/>Allocated chunk of 0x100 bytes at 0x016D0748 <br \/>Allocated chunk of 0x58 bytes at 0x016D0850 <br \/>Allocated chunk of 0x100 bytes at 0x016D08B0 \n<br \/>Press return to continue\n<\/p><\/div><\/pre>\n<div>WinDBG shows that the last 2 allocations are not part of LFH (which means LFH is not active yet).&#160;&#160; We can also see that these allocations are taken from the large free chunk at the end of the segment (thus no longer taking already freed chunks that might have been part of the freelist)<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\n0:003&gt; !heap -x 0x016D08B0 \n    <br \/>Entry User Heap Segment Size PrevSize Unused Flags <br \/>----------------------------------------------------------------------------- <br \/>016d08a8 016d08b0 016c0000 016c0000 108 60 8 busy\n\n<p>0:003&gt; !heap -x 0x016D0850     <br \/><\/p><p>Entry User Heap Segment Size PrevSize Unused Flags <br \/>----------------------------------------------------------------------------- <br \/>016d0848 016d0850 016c0000 016c0000 60 108 8 busy\n<\/p><\/div><\/pre>\n<div>Next, the application will cause the necessary layout.&#160; As a segment doesn't necessarily want to keep chunks of the same bucket size together, and operates in a first ask, first serve manner (unlike the LFH), the 3 allocations should be placed right next to each other:<\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\nAllocated chunk of 0x100 bytes at 0x016D09B8 <br \/>Allocated chunk of 0x58 bytes at 0x016D0AC0, filled with 'A' <br \/>Allocated chunk of 0x100 bytes at 0x016D0B20 \n<br \/>Press return to continue\n  <\/div><\/pre>\n<p>Great! We can use WinDBG to confirm that the 3 chunks are adjacent indeed, and that the middle chunk (0x58) is filled with A's<\/p>\n<p>(from output of !heap -p -h 0x016C0000)<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>016d09b0 0021 0021 [00] 016d09b8 00100 - (busy)    <br \/>016d0ab8 000c 0021 [00] 016d0ac0 00058 - (busy)<br \/>016d0b18 0021 000c [00] 016d0b20 00100 - (busy)\n<\/p><p>0:001&gt; dd 0x016d0ac0 L 0x58\/4     <br \/>016d0ac0 41414141 41414141 41414141 41414141 <br \/>016d0ad0 41414141 41414141 41414141 41414141 <br \/>016d0ae0 41414141 41414141 41414141 41414141 <br \/>016d0af0 41414141 41414141 41414141 41414141 <br \/>016d0b00 41414141 41414141 41414141 41414141 <br \/>016d0b10 41414141 41414141\n  <\/p><\/pre>\n<p>Next, the 0x58 byte chunk will be freed (which means it should end up on the freelist, and not merged with an adjacent free chunk as long as we don't free the adjacent 0x100 byte chunks ourselves).&#160; Finally, a new allocation request for 0x58 is supposed to take that position back.&#160; The example application will populate it with B's:<\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>Free chunk of 0x58 bytes at 0x016D0AC0 <br \/>Allocated chunk of 0x58 bytes at 0x016D0AC0, filled with 'B' \n    <br \/>Done...    <\/p><\/pre>\n<p>WinDBG:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\n0:001&gt; dd 0x016d0ac0 L 0x58\/4     <br \/>016d0ac0 42424242 42424242 42424242 42424242 <br \/>016d0ad0 42424242 42424242 42424242 42424242 <br \/>016d0ae0 42424242 42424242 42424242 42424242 <br \/>016d0af0 42424242 42424242 42424242 42424242 <br \/>016d0b00 42424242 42424242 42424242 42424242 <br \/>016d0b10 42424242 42424242\n\n<\/div><\/pre>\n<p>Bingo.<\/p>\n<h4>BEA_Alloc4<\/h4>\n<p>Let's take it one step further.<\/p>\n<p>This time we'll free a 0x58 byte chunk, and we'll try to use a 0x80 byte allocation (where we only control the last 4 dwords), to control the exact 4 first dwords in the original 0x58 byte chunk. (I know, replacing one object with another object of a different size sounds kinky... but hey, who knows this could be useful one time ... or not)<\/p>\n<div>The approach is pretty much the same: we'll start by (trying) to exhaust the freelist for the sizes that we are going to use, to make sure we have better control over what will be returned when we ask for a chunk of those sizes.&#160; <\/div>\n<div>What is different in this case, is the layout we need to allow magic to happen - i.e. to take the first 4 dwords of the 0x58 byte chunk using the last 4 dwords of the 0x80 byte allocation.<\/div>\n<div><\/div>\n<div>The idea is to try to force 2 freed chunks to merge (by placing them next to each other and then freeing both).&#160; The so-called &quot;vulnerable&quot; object that gets freed in our imaginary &quot;use after free&quot; scenario is 0x58 bytes, and the goal is to to control the first 4 dwords.&#160; The object we can use to replace it with is 0x80 bytes, and we'll pretend we can only control the last 4 dwords of that one.&#160; In other words, we have to make sure that we position those 4 dwords with surgical precision, making sure that the &quot;overlap&quot; will happen in the right place.&#160;&#160; <\/div>\n<div><\/div>\n<div>I generally suck at math, but after spending some time on the abacus, finger counting and scratching my head, I came up with the complex formula that results in trying to position a 0x80-4-4-4-4-8 = 0x68 byte object before the 0x58 byte object.&#160; The 4 times 4 bytes are needed to cause overlap, and the additional 8 bytes are there to compensate for the chunk header of the 0x58 byte chunk that sits before the contents of the 0x58 byte chunk, and is thus also consuming space in memory.&#160;&#160; <\/div>\n<div>This means that we also have to make sure to remove 0x68 byte chunks from the free list in order to increase control over allocations of that size.&#160; <\/div>\n<div><\/div>\n<div>We'll create a layout that consists of 4 allocations:&#160; our 'magic' 0x68 and 0x58 objects in the middle, surrounded by 2 other objects, to avoid that a merge of one of the 2 in the middle will cause us to lose control when things start to merge with the wrong objects. We'll also cause a little bit more allocations to try to exhaust the heap, as some of these sizes may be popular sizes.&#160; <\/div>\n<div><\/div>\n<div>(Again, the number of allocations you need to properly clear out the free list depends on the applicaiton, the context, basically on what is already free at that time)<\/div>\n<div><\/div>\n<div>Let's see what it looks like:<\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>\nC:\\Users\\corelan\\Desktop\\vc++\\win10\\BEA_Alloc4\\Release&gt;BEA_Alloc4.exe<\/p><p>Default process heap found at 0x010D0000\n<\/p><div>Press a key to start...<\/div>\n<div>&lt;...snip...&gt;<\/div>    <div>Allocated chunk of 0x68 bytes at 0x010E1D68<\/div><div>Allocated chunk of 0x58 bytes at 0x010E1DD8\n<\/div><div>Allocated chunk of 0x80 bytes at 0x010E1E38\n<\/div><div>Allocated chunk of 0x68 bytes at 0x010E1EC0\n<\/div><div>Allocated chunk of 0x58 bytes at 0x010E1F30\n<\/div><div>Allocated chunk of 0x80 bytes at 0x010E1F90\n<\/div><div>Allocated chunk of 0x68 bytes at 0x010E2018<\/div>\n\n<div>Press return to continue<\/div><\/pre>\n<div>(Check the last 3 chunks in WinDBG (using !heap -x &lt;address&gt;) to make sure that none of them is LFH managed at this point.)<\/div>\n<div><\/div>\n<div>Next, the application creates the initial layout (0x80 \/\/ 0x68 \/\/ 0x58 \/\/ 0x80).&#160; The first and last one are just there to prevent the 0x68 and 0x58 sized chunks to accidentally merge with the wrong one. <\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\nAllocated start chunk (0x80 bytes) at 0x010E2088  <div>Allocated first chunk (0x68 bytes) at 0x010E2110\n<\/div><div>Allocated second 'vulnerable' chunk (0x58 bytes) at 0x010E2180, filled with 'A'\n<\/div><div>Allocated end chunk (0x80 bytes) at 0x010E21E0<\/div>\n<div>Press return to continue<\/div>\n<\/div><\/pre>\n<div>WinDBG (output from !heap -p -h &lt;address of default process heap&gt;):<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 010e2080 0011 000e&#160; [00]&#160;&#160; 010e2088&#160;&#160;&#160; 00080 - (busy)    <div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 010e2108 000e 0011&#160; [00]&#160;&#160; 010e2110&#160;&#160;&#160; 00068 - (busy)\n<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 010e2178 000c 000e&#160; [00]&#160;&#160; 010e2180&#160;&#160;&#160; 00058 - (busy)\n<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 010e21d8 0011 000c&#160; [00]&#160;&#160; 010e21e0&#160;&#160;&#160; 00080 - (busy)<\/div><\/div><\/div><\/pre>\n<div>Sure enough, the 4 chunks are in the right place.&#160; When the 'vulnerable' 0x58 byte chunk gets freed, we'll also cause the first one to free ourselves.&#160; This should merge the 2 together.<\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\nFree chunk of 0x58 bytes at 0x010E2180\n<div>Free first chunk of 0x68 bytes at 0x010E2110<\/div>  <div>Press return to continue<\/div><\/div><\/pre>\n<div>WinDBG shows that we now have one big free chunk at 0x010E2110, of 0xc8 bytes.&#160; If we dump it, we see the original 0x68 chunk followed by the vulnerable 0x58 byte chunk.<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div> 0:003&gt; !heap -p -a 0x010E2110\n<div>&#160;&#160;&#160; address 010e2110 found in  <\/div><div>&#160;&#160;&#160; _HEAP @ 10d0000\n<\/div><div>&#160;&#160;&#160;&#160;&#160; HEAP_ENTRY Size Prev Flags&#160;&#160;&#160; UserPtr UserSize - state\n<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 010e2108 001a 0000&#160; [00]&#160;&#160; 010e2110&#160;&#160;&#160; 000c8 - (free)<\/div>\n<div>0:003&gt; dd 0x010E2110 L 0xc8\/4<\/div><div>010e2110&#160; 010e2268 010de858 00000000 00000000  <\/div><div>010e2120&#160; 00000000 00000000 00000000 00000000<\/div><div>010e2130&#160; 00000000 00000000 00000000 00000000<\/div><div>010e2140&#160; 00000000 00000000 00000000 00000000<\/div><div>010e2150&#160; 00000000 00000000 00000000 00000000<\/div><div>010e2160&#160; 00000000 00000000 00000000 00000000<\/div><div>010e2170&#160; 00000000 00000000 0c00000c 00008812<\/div><div>010e2180&#160; 010e2268 010de858 41414141 41414141<\/div><div>010e2190&#160; 41414141 41414141 41414141 41414141<\/div><div>010e21a0&#160; 41414141 41414141 41414141 41414141  <\/div><div>010e21b0&#160; 41414141 41414141 41414141 41414141<\/div><div>010e21c0&#160; 41414141 41414141 41414141 41414141<\/div><div>010e21d0&#160; 41414141 41414141<\/div>\n<\/div><\/pre>\n<div>Finally, our 0x80 byte allocation is now supposed to take the first 0x80 bytes of this free chunk, overwriting the first 4 dwords inside the chunk with A's with the last 4 dwords of the 0x80 byte chunk. <\/div>\n<div><\/div>\n<div>App:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>  <div>Allocated chunk of 0x80 bytes at 0x010E2110, filled with 'B'<\/div>  <div>Done...<\/div><\/div><\/pre>\n<div>WinDBG:<\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>  <div>0:001&gt; !heap -p -a 0x010E2110<\/div><div>&#160;&#160;&#160; address 010e2110 found in<\/div><div>&#160;&#160;&#160; _HEAP @ 10d0000<\/div><div>&#160;&#160;&#160;&#160;&#160; HEAP_ENTRY Size Prev Flags&#160;&#160;&#160; UserPtr UserSize - state<\/div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 010e2108 0011 0000&#160; [00]&#160;&#160; 010e2110&#160;&#160;&#160; 00080 - (busy)<\/div><\/div><div>\n  <div>0:001&gt; dd 0x010E2110 L 0xc8\/4<\/div><div>010e2110&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2120&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2130&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2140&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2150&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2160&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2170&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2180&#160; 42424242 42424242 42424242 42424242<\/div><div>010e2190&#160; 6a309389 0000880d 010dee10 010d1db8<\/div><div>010e21a0&#160; 41414141 41414141 41414141 41414141<\/div><div>010e21b0&#160; 41414141 41414141 41414141 41414141  <\/div><div>010e21c0&#160; 41414141 41414141 41414141 41414141<\/div><div>010e21d0&#160; 41414141 41414141<\/div><\/div><\/pre>\n<div>Damn, it looks like we missed our target with 8 bytes (as I said, I suck at math... but perhaps I should have used a 0x60 byte chunk instead of 0x68... )&#160; anyway I'm sure you get the point...&#160; <\/div>\n<div><\/div>\n<div>Nice - but all of this was only possible because none of the sizes involved were managed by the LFH already, and because we were able to avoid the LFH from being triggered.&#160; <\/div>\n<div><\/div>\n<div>Perhaps this is the right time to look at the LFH under WIndows 10 and see how it behaves.&#160; After all, we may not always have the luxury of avoiding the LFH in the first place.<\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<h3>The Front-End Allocator - LFH<\/h3>\n<h4>LFH_Alloc1<\/h4>\n<p>In this first exercise, we'll examine if it still takes 0x12 (18) consecutive allocations for a size in the same bucket before the LFH will start taking care of allocations and frees of those sizes. <\/p>\n<p>In order to avoid any influencing or assumptions, I'll use chunksizes that has not been allocated yet. (0x1500 bytes, 0x2100 bytes, 0x3000 bytes, 0x800 bytes)<\/p>\n<p>I'll combine a couple of tests in this test:<\/p>\n<ol>\n<li><font color=\"#ffffff\">check how many allocations it takes before LFH kicks in<\/font><\/li>\n<li><font color=\"#ffffff\">see if the LFH trigger is influenced when an allocation happens of a different bucket size during the series of allocations<\/font><\/li>\n<li><font color=\"#ffffff\">see if the LFH trigger is influenced when a free happens during the allocations, of a chunk in a different bucket\/of a different size<\/font><\/li>\n<li><font color=\"#ffffff\">see if the LFH trigger is influenced when a chunk of the same bucket is freed again, during the series of allocations<\/font><\/li>\n<\/ol>\n<p><strong><span style=\"text-decoration: underline\">Step1: how many allocations are needed to trigger LFH<\/span><\/strong><\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10\\LFH_Alloc1\\Release&gt;LFH_Alloc1.exe \nDefault process heap found at 0x00D30000 Press a key to start...\n\n\n[1] Allocated chunk of 0x1500 bytes at 0x00D4CF68\n[2] Allocated chunk of 0x1500 bytes at 0x00D4E470 \n[3] Allocated chunk of 0x1500 bytes at 0x00D4F978 \n[4] Allocated chunk of 0x1500 bytes at 0x00D50E80 \n[5] Allocated chunk of 0x1500 bytes at 0x00D52388 \n[6] Allocated chunk of 0x1500 bytes at 0x00D53890 \n[7] Allocated chunk of 0x1500 bytes at 0x00D54D98 \n[8] Allocated chunk of 0x1500 bytes at 0x00D562A0 \n[9] Allocated chunk of 0x1500 bytes at 0x00D577A8 \n[10] Allocated chunk of 0x1500 bytes at 0x00D58CB0 \n[11] Allocated chunk of 0x1500 bytes at 0x00D5A1B8 \n[12] Allocated chunk of 0x1500 bytes at 0x00D5B6C0 \n[13] Allocated chunk of 0x1500 bytes at 0x00D5CBC8 \n[14] Allocated chunk of 0x1500 bytes at 0x00D5E0D0 \n[15] Allocated chunk of 0x1500 bytes at 0x00D5F5D8 \n[16] Allocated chunk of 0x1500 bytes at 0x00D60AE0 \n[17] Allocated chunk of 0x1500 bytes at 0x00D61FE8 \n[18] Allocated chunk of 0x1500 bytes at 0x00D6B348 \n[19] Allocated chunk of 0x1500 bytes at 0x00D64A20 \n[20] Allocated chunk of 0x1500 bytes at 0x00D69E40 \n[21] Allocated chunk of 0x1500 bytes at 0x00D6C850 \n[22] Allocated chunk of 0x1500 bytes at 0x00D63518 \n[23] Allocated chunk of 0x1500 bytes at 0x00D6DD58 \n[24] Allocated chunk of 0x1500 bytes at 0x00D67430 \n[25] Allocated chunk of 0x1500 bytes at 0x00D6F260 \n[26] Allocated chunk of 0x1500 bytes at 0x00D65F28 \n[27] Allocated chunk of 0x1500 bytes at 0x00D70768 \n[28] Allocated chunk of 0x1500 bytes at 0x00D68938 \n[29] Allocated chunk of 0x1500 bytes at 0x00D71C70 \n[30] Allocated chunk of 0x1500 bytes at 0x00D77438 \nPress return to continue<\/p><\/pre>\n<p>If you pay close attention to the addresses, you can see a bigger gap between allocations 17 and 18.&#160; This is a good indication that allocations are no longer individual chunks inside a normal segment, but are now being consumed from an LFH subsegment.&#160; To be sure, let's validate the findings in WinDBG.<\/p>\n<p>Simply run !heap -x&#160; on all addresses (starting from the first one in the list), until you find the first one that has the &quot;LFH&quot; marker.<\/p>\n<p>Allocation 17:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:001&gt; !heap -x 0x00D61FE8 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags <\/p><p>----------------------------------------------------------------------------- <\/p><p>00d61fe0 00d61fe8 00d30000 00d30000 1508 1508 8 busy<\/p><\/pre>\n<p>Allocation 18:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:001&gt; !heap -x 0x00D6B348 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags <\/p><p>----------------------------------------------------------------------------- <\/p><p>00d6b340 00d6b348 00d30000 00d3ae28 1508 - 8 LFH;busy<\/p><\/pre>\n<p>So - it looks like the LFH takes over with allocation 18.<\/p>\n<p><strong><span style=\"text-decoration: underline\"><\/p>\n<p><\/span><\/strong><\/p>\n<p><strong><span style=\"text-decoration: underline\">Step 2: will the LFH trigger be influenced if another allocation (of a size in a different bucket) occurs in the series of 18 allocations.<\/span><\/strong><\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\">[1] Allocated chunk of 0x2100 bytes at 0x00D93500 \n[2] Allocated chunk of 0x2100 bytes at 0x00D95608 \n[3] Allocated chunk of 0x2100 bytes at 0x00D97710 \n[4] Allocated chunk of 0x2100 bytes at 0x00D99818 \n[5] Allocated chunk of 0x2100 bytes at 0x00D9B920 \n[6] Allocated chunk of 0x2100 bytes at 0x00D9DA28 \n[7] Allocated chunk of 0x2100 bytes at 0x00D9FB30 \n[8] Allocated chunk of 0x2100 bytes at 0x00DA1C38 \n[9] Allocated chunk of 0x2100 bytes at 0x00DA3D40 \n[10] Allocated chunk of 0x2100 bytes at 0x00DA5E48 \nAllocated chunk of 0x300 bytes at 0x00D49450 \n[11] Allocated chunk of 0x2100 bytes at 0x00DA7F50 \n[12] Allocated chunk of 0x2100 bytes at 0x00DAA058 \n[13] Allocated chunk of 0x2100 bytes at 0x00DAC160 \n[14] Allocated chunk of 0x2100 bytes at 0x00DAE268 \n[15] Allocated chunk of 0x2100 bytes at 0x00DB0370 \n[16] Allocated chunk of 0x2100 bytes at 0x00DB2478 \n[17] Allocated chunk of 0x2100 bytes at 0x00DB4580 \n[18] Allocated chunk of 0x2100 bytes at 0x00DC10D8 \n[19] Allocated chunk of 0x2100 bytes at 0x00DBAAC0 \n[20] Allocated chunk of 0x2100 bytes at 0x00DC32E0 \nPress return to continue<\/pre>\n<p>Focusing on allocation 17 and 18 (of 0x2100 bytes), we can see that alloc 17 was not LFH yet, but the 18th one did it again, despite the allocation of a 0x300 byte chunk in the middle of the series.<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:001&gt; !heap -x 0x00DB4580 <p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00db4578 00db4580 00d30000 00d30000 2108 2108 8 busy<\/p><p>\n<\/p><p>0:001&gt; !heap -x 0x00DC10D8 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00dc10d0 00dc10d8 00d30000 00d3ae78 2208 - 3f LFH;busy<\/p><\/pre>\n<p>Interesting indeed \ud83d\ude42<\/p>\n<p><strong><span style=\"text-decoration: underline\">Step 3: will a free (of a different chunk size) influence the LFH trigger ?<\/span><\/strong><\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>[1] Allocated chunk of 0x3000 bytes at 0x00DD6690 <\/p><p>[2] Allocated chunk of 0x3000 bytes at 0x00DD9698 \n[3] Allocated chunk of 0x3000 bytes at 0x00DDC6A0 \n[4] Allocated chunk of 0x3000 bytes at 0x00DDF6A8 \n[5] Allocated chunk of 0x3000 bytes at 0x00DE26B0 \n[6] Allocated chunk of 0x3000 bytes at 0x00DE56B8 \n[7] Allocated chunk of 0x3000 bytes at 0x00DE86C0 \n[8] Allocated chunk of 0x3000 bytes at 0x00DEB6C8 \n[9] Allocated chunk of 0x3000 bytes at 0x00DEE6D0 \n[10] Allocated chunk of 0x3000 bytes at 0x00DF16D8 \nFreed chunk at 0x00D49C80 \nFreed chunk at 0x00D4A188 \n[11] Allocated chunk of 0x3000 bytes at 0x00DF46E0 \n[12] Allocated chunk of 0x3000 bytes at 0x00DF76E8 \n[13] Allocated chunk of 0x3000 bytes at 0x00DFA6F0 \n[14] Allocated chunk of 0x3000 bytes at 0x00DFD6F8 \n[15] Allocated chunk of 0x3000 bytes at 0x00E00700 \n[16] Allocated chunk of 0x3000 bytes at 0x00E03708 \n[17] Allocated chunk of 0x3000 bytes at 0x00E06710 \n[18] Allocated chunk of 0x3000 bytes at 0x00E0C748 \n[19] Allocated chunk of 0x3000 bytes at 0x00E15760 \n[20] Allocated chunk of 0x3000 bytes at 0x00E1B770 \nDone...<\/p><\/pre>\n<p>WinDBG (focus on allocation 17 and 18 again):<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:001&gt; !heap -x 0x00E06710 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00e06708 00e06710 00d30000 00d30000 3008 3008 8 busy<\/p>\n<p>0:001&gt; !heap -x 0x00E0C748 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00e0c740 00e0c748 00d30000 00d3aea0 3008 - 8 LFH;busy<\/p><\/pre>\n<p>Interesting once more:)<\/p>\n<p><strong><span style=\"text-decoration: underline\">Step 4: free a chunk from the same bucket during the allocation series.<\/span><\/strong><\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>[1] Allocated chunk of 0x800 bytes at 0x004EAE70 <\/p><p>[2] Allocated chunk of 0x800 bytes at 0x0053E910 \n[3] Allocated chunk of 0x800 bytes at 0x0053F118 \n[4] Allocated chunk of 0x800 bytes at 0x0053F920 \n[5] Allocated chunk of 0x800 bytes at 0x00540128 \n[6] Allocated chunk of 0x800 bytes at 0x00540930 \n[7] Allocated chunk of 0x800 bytes at 0x00541138 \n[8] Allocated chunk of 0x800 bytes at 0x00541940 \n[9] Allocated chunk of 0x800 bytes at 0x00542148 \n[10] Allocated chunk of 0x800 bytes at 0x00542950 \nFreed chunk at 0x00542950 \n[11] Allocated chunk of 0x800 bytes at 0x00542950 \n[12] Allocated chunk of 0x800 bytes at 0x00543158 \n[13] Allocated chunk of 0x800 bytes at 0x00543960 \n[14] Allocated chunk of 0x800 bytes at 0x00544168 \n[15] Allocated chunk of 0x800 bytes at 0x00544970 \n[16] Allocated chunk of 0x800 bytes at 0x00545178 \n[17] Allocated chunk of 0x800 bytes at 0x00545980 \n[18] Allocated chunk of 0x800 bytes at 0x009F0070 \n[19] Allocated chunk of 0x800 bytes at 0x009F2090 \n[20] Allocated chunk of 0x800 bytes at 0x009F68D8 \nDone...<\/p><\/pre>\n<p>WinDBG (looking again at allocation 17 and 18)<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:004&gt; !heap -x 0x00545980 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00545978 00545980 00450000 00450000 808 808 8 busy<\/p>\n<p>0:004&gt; !heap -x 0x009F0070 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n009f0068 009f0070 00450000 00458c60 808 - 8 LFH;busy<\/p><\/pre>\n<p>Interestingly enough, the free did not really impact the LFH trigger at all.&#160; 18 allocations still did the trick.<\/p>\n<p>I guess more exhaustive testing is needed to confirm this behaviour, including checking what happens if there are more frees etc... but at least we are able to see some kind of pattern that indicates it may be more difficult to avoid that the LFH will be get enabled eventually, especially if you have no other option that to cause a certain number of allocations (more than 18) of chunks in the same bucket.&#160; <\/p>\n<p>If you know of a way to prevent this from happening, please let me know \ud83d\ude42<\/p>\n<h4>LFH_Alloc2<\/h4>\n<p>In the second exercise, we'll see if the LFH still behaves the same way as under Windows 7 - i.e. returning freed chunks in a LIFO manner.&#160;&#160; We'll activate the LFH using 20 allocations of 0x500 bytes.&#160; The last one will be freed, and then another allocation of 0x500 bytes will happen. <\/p>\n<p>The goal is to see if the last one to be freed will be the first one to be returned again. (LIFO).<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10\\LFH_Alloc2\\Release&gt;LFH_Alloc2.exe <\/p><p>Default process heap found at 0x008D0000 \nPress a key to start...\n<\/p><p>[1] Allocated chunk of 0x500 bytes at 0x008E0440 <\/p><p>[2] Allocated chunk of 0x500 bytes at 0x008E0948 \n[3] Allocated chunk of 0x500 bytes at 0x008E0E50 \n[4] Allocated chunk of 0x500 bytes at 0x008E1358 \n[5] Allocated chunk of 0x500 bytes at 0x008E1860 \n[6] Allocated chunk of 0x500 bytes at 0x008E1D68 \n[7] Allocated chunk of 0x500 bytes at 0x008E2270 \n[8] Allocated chunk of 0x500 bytes at 0x008E2778 \n[9] Allocated chunk of 0x500 bytes at 0x008E2C80 \n[10] Allocated chunk of 0x500 bytes at 0x008E3188 \n[11] Allocated chunk of 0x500 bytes at 0x008E3690 \n[12] Allocated chunk of 0x500 bytes at 0x008E3B98 \n[13] Allocated chunk of 0x500 bytes at 0x008E40A0 \n[14] Allocated chunk of 0x500 bytes at 0x008E45A8 \n[15] Allocated chunk of 0x500 bytes at 0x008E4AB0 \n[16] Allocated chunk of 0x500 bytes at 0x008E4FB8 \n[17] Allocated chunk of 0x500 bytes at 0x008E54C0 \n[18] Allocated chunk of 0x500 bytes at 0x008E7D28 \n[19] Allocated chunk of 0x500 bytes at 0x008E5EF8 \n[20] Allocated chunk of 0x500 bytes at 0x008E6E10 \nPress return to continue\n<\/p><p>Freed chunk at 0x008E6E10 <\/p><p>Press return to continue\n<\/p><p>Allocated chunk of 0x500 bytes at 0x008E9148 <\/p><p>Press return to continue<\/p><\/pre>\n<div>In WinDBG, we can see that the LFH was indeed activated, but it also looks like the LIFO is behavior from Windows 7 is no longer there. <\/div>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><div>\n0:003&gt; !heap -x 0x008E6E10     <br \/>Entry User Heap Segment Size PrevSize Unused Flags <br \/>----------------------------------------------------------------------------- <br \/>008e6e08 008e6e10 008d0000 008d8d90 508 - 0 LFH;free\n\n  <p>0:003&gt; !heap -x 0x008E9148 <br \/>Entry User Heap Segment Size PrevSize Unused Flags <br \/>----------------------------------------------------------------------------- <br \/>008e9140 008e9148 008d0000 008d8d90 508 - 8 LFH;busy\n<\/p><\/div><\/pre>\n<p>Perhaps causing a series of allocations of 0x500 byte will allow us to take the freed chunk back.&#160; Press return to cause another 20 allocations of 0x500 bytes and see what happens:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>Allocated chunk of 0x500 bytes at 0x008E59F0 <\/p><p>Allocated chunk of 0x500 bytes at 0x008E7318 \nAllocated chunk of 0x500 bytes at 0x008E8738 \nAllocated chunk of 0x500 bytes at 0x008E6400 \nAllocated chunk of 0x500 bytes at 0x008E8C40 \nAllocated chunk of 0x500 bytes at 0x008E6908 \nAllocated chunk of 0x500 bytes at 0x008E7820 \nAllocated chunk of 0x500 bytes at 0x008E8230 \nAllocated chunk of 0x500 bytes at 0x008E6E10 \n--- got it back --- \nAllocated chunk of 0x500 bytes at 0x008EC740 \nAllocated chunk of 0x500 bytes at 0x008EEA78 \nAllocated chunk of 0x500 bytes at 0x008EBD30 \nAllocated chunk of 0x500 bytes at 0x008EC238 \nAllocated chunk of 0x500 bytes at 0x008EDB60 \nAllocated chunk of 0x500 bytes at 0x008EF488 \nAllocated chunk of 0x500 bytes at 0x008ECC48 \nAllocated chunk of 0x500 bytes at 0x008F0DB0 \nAllocated chunk of 0x500 bytes at 0x008E99F8 \nAllocated chunk of 0x500 bytes at 0x008EEF80 \nAllocated chunk of 0x500 bytes at 0x008EB828 \nPress return to continue<\/p><\/pre>\n<p>In this case, it took another 9 allocations to get the freed chunk back.&#160; In fact, if you'd run the same application a couple of times, you'll see that the number of times it takes to get the freed chunk back, varies largely between 0 (sometimes you'll get it back LIFO style) and never (at least, not in the first 20 allocations or so)... but in most cases I got it back within the first 10 allocations.&#160; (A lot more structured testing would be needed to find the sweet spot that would provide some sort of predictability. It'll probably never be 100% reliable, but it may not be too messy either.)<\/p>\n<p><strong><em><font color=\"#ffff00\">Update (7\/7\/2016) - I added &quot;LFH_TakeBack&quot; to the github repository, which will automate some statistic gathering.&#160; For each chunksize between 8 and 0x4000, it will enable LFH, alloc a chunk and free it again, and then measure how many allocations are needed to take it back.&#160; The application calculates an average, a minimum and maximum number of tries, and also keeps track how many times the object was not taken back within the first 2000 allocations.<\/font><\/em><\/strong><\/p>\n<p><strong><em><font color=\"#ffff00\">After running the app, it looks like the maximum number of allocations needed sits around 50.<\/font> <\/em><\/strong><\/p>\n<p><strong><em><\/em><\/strong><\/p>\n<p>Anyway, looking at the addresses of the allocations, it also looks like the chunks are no longer adjacent (as they were in Windows 7, at least as long as the chunks are inside the same subsegment). <\/p>\n<p>This will certainly make it more complex to create a specific layout\/sequence of objects when the LFH is enabled.<\/p>\n<h4>LFH_Alloc3 <\/h4>\n<p>Is LFH still limited to 0x4000 byte chunks (max)?<\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10\\LFH_Alloc3\\Release&gt;LFH_Alloc3.exe <\/p><p>Default process heap found at 0x00930000 \nPress a key to start...\n<\/p><p>[1] Allocated chunk of 0x4000 bytes at 0x00940FF8 <\/p><p>[2] Allocated chunk of 0x4000 bytes at 0x00945000 \n[3] Allocated chunk of 0x4000 bytes at 0x00949008 \n[4] Allocated chunk of 0x4000 bytes at 0x0094D010 \n[5] Allocated chunk of 0x4000 bytes at 0x00951018 \n[6] Allocated chunk of 0x4000 bytes at 0x00955020 \n[7] Allocated chunk of 0x4000 bytes at 0x00959028 \n[8] Allocated chunk of 0x4000 bytes at 0x0095D030 \n[9] Allocated chunk of 0x4000 bytes at 0x00961038 \n[10] Allocated chunk of 0x4000 bytes at 0x00965040 \n[11] Allocated chunk of 0x4000 bytes at 0x00969048 \n[12] Allocated chunk of 0x4000 bytes at 0x0096D050 \n[13] Allocated chunk of 0x4000 bytes at 0x00971058 \n[14] Allocated chunk of 0x4000 bytes at 0x00975060 \n[15] Allocated chunk of 0x4000 bytes at 0x00979068 \n[16] Allocated chunk of 0x4000 bytes at 0x0097D070 \n[17] Allocated chunk of 0x4000 bytes at 0x00981078 \n[18] Allocated chunk of 0x4000 bytes at 0x0098D0B8 \n[19] Allocated chunk of 0x4000 bytes at 0x009950C8 \n[20] Allocated chunk of 0x4000 bytes at 0x009910C0 \nPress return to continue<\/p>\n<p>[1] Allocated chunk of 0x4008 bytes at 0x009C7008 <\/p><p>[2] Allocated chunk of 0x4008 bytes at 0x009CB018 \n[3] Allocated chunk of 0x4008 bytes at 0x009CF028 \n[4] Allocated chunk of 0x4008 bytes at 0x009D3038 \n[5] Allocated chunk of 0x4008 bytes at 0x009D7048 \n[6] Allocated chunk of 0x4008 bytes at 0x009DB058 \n[7] Allocated chunk of 0x4008 bytes at 0x009DF068 \n[8] Allocated chunk of 0x4008 bytes at 0x009E3078 \n[9] Allocated chunk of 0x4008 bytes at 0x009E7088 \n[10] Allocated chunk of 0x4008 bytes at 0x009EB098 \n[11] Allocated chunk of 0x4008 bytes at 0x009EF0A8 \n[12] Allocated chunk of 0x4008 bytes at 0x009F30B8 \n[13] Allocated chunk of 0x4008 bytes at 0x009F70C8 \n[14] Allocated chunk of 0x4008 bytes at 0x009FB0D8 \n[15] Allocated chunk of 0x4008 bytes at 0x009FF0E8 \n[16] Allocated chunk of 0x4008 bytes at 0x00A030F8 \n[17] Allocated chunk of 0x4008 bytes at 0x00A07108 \n[18] Allocated chunk of 0x4008 bytes at 0x00A0B118 \n[19] Allocated chunk of 0x4008 bytes at 0x00A0F128 \n[20] Allocated chunk of 0x4008 bytes at 0x00A13138 \nPress return to continue<\/p><\/pre>\n<p>WinDBG: 0x4000 bytes<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:001&gt; !heap -x 0x00981078 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00981070 00981078 00930000 00930000 4008 4008 8 busy<\/p>\n<p>0:001&gt; !heap -x 0x0098D0B8 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n0098d0b0 0098d0b8 00930000 00938c48 4008 - 8 LFH;busy<\/p><\/pre>\n<p>WinDBG: 0x4008 bytes<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:001&gt; !heap -x 0x00A07108 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00a07100 00a07108 00930000 00930000 4010 4010 8 busy\n\n<\/p><p>0:001&gt; !heap -x 0x00A0B118 <\/p><p>Entry User Heap Segment Size PrevSize Unused Flags \n----------------------------------------------------------------------------- \n00a0b110 00a0b118 00930000 00930000 4010 4010 8 busy<\/p><\/pre>\n<p>Answer:&#160; YES, 0x4000 seems to be the maximum size (just like on Windows 7)<\/p>\n<h4>LFH_TakeBack2<\/h4>\n<p>The LFH_Alloc* exercises demonstrate that chunks are no longer allocated in an consecutive manner inside a LFH subsegment. Of course, this complicates creating a specific layout within the subsegment.&#160;&#160; I still wanted to know if it would be possible to replace the memory space used by a LFH chunk by an LFH allocation of a size from a different bucket. As an example, can I take the space of a 0x58 byte chunk using a 0x88 byte allocation, within the LFH.<\/p>\n<p>As the LFH subsegments are used to keep chunks of the same bucket size together, this would require clearing out the entire subsegment used for storing the vulnerable object, and hopefully the Heap Manager will reuse those pages for another subsegment (allocations for a different bucket size).<\/p>\n<p>LFH_TakeBack2 demonstrates if it works or not.&#160;&#160; The idea is to try to place the &quot;vulnerable&quot; object in a subsegment where you control all the other chunks.&#160; As soon as the vulnerable object gets freed, you cause all the other chunks to be freed as well.&#160; Hopefully, this will also release the entire subsegment and its pages, so they can be reused again (even for a subsegment associated with chunksizes that fall in a different bucket). <\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10_heap\\LFH_TakeBack2\\Release&gt;LFH_TakeBack2.exe\n  <br \/>Vulnerable object of 0x00000058 bytes at 0x01136B98, filled with 'A'\n<br \/>Allocations done. Press return to start free process<\/p><\/pre>\n<p>WinDBG:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; dd 0x01136B98<br \/>01136b98&#160; 41414141 41414141 41414141 41414141<br \/>01136ba8&#160; 41414141 41414141 41414141 41414141<br \/>01136bb8&#160; 41414141 41414141 41414141 41414141<br \/>01136bc8&#160; 41414141 41414141 41414141 41414141<br \/>01136bd8&#160; 41414141 41414141 41414141 41414141<br \/>01136be8&#160; 41414141 41414141 07fe9621 88011d00<br \/>01136bf8&#160; 00000000 00000000 00000000 00000000<br \/>01136c08&#160; 00000000 00000000 00000000 00000000\n\n  <br \/>0:003&gt; !heap -p -a 0x01136B98<br \/>&#160;&#160;&#160; address 01136b98 found in<br \/>&#160;&#160;&#160; _HEAP @ e30000<br \/>&#160;&#160;&#160;&#160;&#160; HEAP_ENTRY Size Prev Flags&#160;&#160;&#160; UserPtr UserSize - state<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 01136b90 000c 0000&#160; [00]&#160;&#160; 01136b98&#160;&#160;&#160; 00058 - (busy)\n<\/p><p>&#160; <br \/>0:003&gt; !heap -x 0x01136B98<br \/>Entry&#160;&#160;&#160;&#160; User&#160;&#160;&#160;&#160;&#160; Heap&#160;&#160;&#160;&#160;&#160; Segment&#160;&#160;&#160;&#160;&#160;&#160; Size&#160; PrevSize&#160; Unused&#160;&#160;&#160; Flags<br \/>-----------------------------------------------------------------------------<br \/>01136b90&#160; 01136b98&#160; 00e30000&#160; 00e45638&#160;&#160;&#160;&#160;&#160;&#160;&#160; 60&#160;&#160;&#160;&#160;&#160; -&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 8&#160; LFH;busy\n<\/p><\/pre>\n<p>Continue with App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>Vulnerable object at 0x01136B98 was freed<br \/>Free done. Press return to start new allocations (size 0x00000088)\n<\/p><p>Allocations done.&#160;&#160; Check if 0x01136B98 contains 'B' now\n<\/p><\/pre>\n<p>WinDBG:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:001&gt; dd 0x01136B98<br \/>01136b98&#160; 42424242 42424242 42424242 42424242<br \/>01136ba8&#160; 42424242 42424242 42424242 42424242<br \/>01136bb8&#160; 42424242 42424242 42424242 42424242  <br \/>01136bc8&#160; 42424242 42424242 42424242 42424242<br \/>01136bd8&#160; 42424242 42424242 42424242 42424242<br \/>01136be8&#160; 42424242 42424242 42424242 42424242<br \/>01136bf8&#160; 42424242 42424242 42424242 42424242<br \/>01136c08&#160; 42424242 42424242 07f296dd 8800bf00\n\n  <br \/>0:001&gt; !heap -x 0x01136B98<br \/>Entry&#160;&#160;&#160;&#160; User&#160;&#160;&#160;&#160;&#160; Heap&#160;&#160;&#160;&#160;&#160; Segment&#160;&#160;&#160;&#160;&#160;&#160; Size&#160; PrevSize&#160; Unused&#160;&#160;&#160; Flags<br \/>-----------------------------------------------------------------------------<br \/>01136b80&#160; 01136b88&#160; 00e30000&#160; 00e38ca0&#160;&#160;&#160;&#160;&#160;&#160;&#160; 90&#160;&#160;&#160;&#160;&#160; -&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 8&#160; LFH;busy \n<\/p><\/pre>\n<p>Size is now 0x90.&#160;&#160; So, the mechanism still works (just like in older Windows versions). Of course, because the sequence of chunks inside a segment is not fully under our control, it will be difficult to control specific bytes of the freed object when you replace it with a different sized chunk.&#160;&#160; <\/p>\n<h3>Large chunks<\/h3>\n<h4>Large_Alloc1<\/h4>\n<p>What do virtualallocdblock chunks\/allocations look like under WIndows 10?<\/p>\n<p>In order to create such chunks, we need to cause HeapAlloc\/RtlAllocateHeap allocations of a size that is larger than the VirtualMemoryThreshold value in the heap header.&#160; In the example application, I am triggering 20 allocations of 0x7ffb0 bytes (which is larger than the 7ff00 byte threshold).<\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10\\Large_Alloc1\\Release&gt;Large_Alloc1.exe <\/p><p>Default process heap found at 0x00E20000 \nPress a key to start...\n<\/p><p>[1] Allocated chunk of 0x7ffb0 bytes at 0x00C48020 <\/p><p>[2] Allocated chunk of 0x7ffb0 bytes at 0x01110020 \n[3] Allocated chunk of 0x7ffb0 bytes at 0x011A1020 \n[4] Allocated chunk of 0x7ffb0 bytes at 0x0123F020 \n[5] Allocated chunk of 0x7ffb0 bytes at 0x01326020 \n[6] Allocated chunk of 0x7ffb0 bytes at 0x013BA020 \n[7] Allocated chunk of 0x7ffb0 bytes at 0x0144C020 \n[8] Allocated chunk of 0x7ffb0 bytes at 0x014D2020 \n[9] Allocated chunk of 0x7ffb0 bytes at 0x0156D020 \n[10] Allocated chunk of 0x7ffb0 bytes at 0x015F4020 \n[11] Allocated chunk of 0x7ffb0 bytes at 0x01680020 \n[12] Allocated chunk of 0x7ffb0 bytes at 0x01712020 \n[13] Allocated chunk of 0x7ffb0 bytes at 0x017AB020 \n[14] Allocated chunk of 0x7ffb0 bytes at 0x0183B020 \n[15] Allocated chunk of 0x7ffb0 bytes at 0x018C9020 \n[16] Allocated chunk of 0x7ffb0 bytes at 0x01957020 \n[17] Allocated chunk of 0x7ffb0 bytes at 0x019EA020 \n[18] Allocated chunk of 0x7ffb0 bytes at 0x01A75020 \n[19] Allocated chunk of 0x7ffb0 bytes at 0x01B09020 \n[20] Allocated chunk of 0x7ffb0 bytes at 0x01B9D020 \nPress return to continue<\/p><\/pre>\n<p>WinDBG: (output of !heap -p -h &lt;address of default process heap&gt;, limited to information related with VirtualAllocdBlocks)<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>VirtualAllocdBlocks @ e2009c <\/p><p>00c48018 10000 0004 [00] 00c48020 7ffb0 - (busy VirtualAlloc) \n01110018 10000 0000 [00] 01110020 7ffb0 - (busy VirtualAlloc) \n011a1018 10000 0000 [00] 011a1020 7ffb0 - (busy VirtualAlloc) \n0123f018 10000 0000 [00] 0123f020 7ffb0 - (busy VirtualAlloc) \n01326018 10000 0000 [00] 01326020 7ffb0 - (busy VirtualAlloc) \n013ba018 10000 0000 [00] 013ba020 7ffb0 - (busy VirtualAlloc) \n0144c018 10000 0000 [00] 0144c020 7ffb0 - (busy VirtualAlloc) \n014d2018 10000 0000 [00] 014d2020 7ffb0 - (busy VirtualAlloc) \n0156d018 10000 0000 [00] 0156d020 7ffb0 - (busy VirtualAlloc) \n015f4018 10000 0000 [00] 015f4020 7ffb0 - (busy VirtualAlloc) \n01680018 10000 0000 [00] 01680020 7ffb0 - (busy VirtualAlloc) \n01712018 10000 0000 [00] 01712020 7ffb0 - (busy VirtualAlloc) \n017ab018 10000 0000 [00] 017ab020 7ffb0 - (busy VirtualAlloc) \n0183b018 10000 0000 [00] 0183b020 7ffb0 - (busy VirtualAlloc) \n018c9018 10000 0000 [00] 018c9020 7ffb0 - (busy VirtualAlloc) \n01957018 10000 0000 [00] 01957020 7ffb0 - (busy VirtualAlloc) \n019ea018 10000 0000 [00] 019ea020 7ffb0 - (busy VirtualAlloc) \n01a75018 10000 0000 [00] 01a75020 7ffb0 - (busy VirtualAlloc) \n01b09018 10000 0000 [00] 01b09020 7ffb0 - (busy VirtualAlloc) \n01b9d018 10000 0000 [00] 01b9d020 7ffb0 - (busy VirtualAlloc)<\/p><\/pre>\n<p>Yes, we can still trigger this kind of allocations.&#160; Due to the nature of this type of allocations they are still placed at the start of a fresh new page (which is why we're seeing the start address alignments).&#160; On the other hand, the gaps between 2 allocations seems to be larger than under Windows 7.&#160; <\/p>\n<p>This means that it will become harder to use this type of allocations to fill up a larger memory region as part of a heap spray.&#160; There will be much bigger holes in between allocations, and the locations of the holes are also non-predictable, which means we may not be able to rely on absolute heap spray addresses as much as we could in Windows 7.<\/p>\n<p>Perhaps a larger series of allocations is needed, and a larger number of runs, to find &quot;sweet spots&quot;, addresses that are allocated more often than others.&#160; Not sure what kind of percentage of predictability we may be able to obtain, but it might be worth the try.<\/p>\n<h4>Large_Alloc2<\/h4>\n<p>So... can we do a precise heap spray under Windows 10?<\/p>\n<p>Well.... yes.&#160; The key is to avoid LFH, and to avoid virtualallocdblocks as well.<\/p>\n<p>Use a &quot;sweet&quot; size and a &quot;sweet&quot; number of allocs to get aligned consecutive allocations (starting at ????0048) as a normal chunk, inside a normal segment.&#160; Perhaps the first few allocations won't start at that aligned address (because there are already some smaller allocations in the segment), but as soon as the allocations trigger the creation of another segment, and you manage to take the first spot, your allocations should be aligned.<\/p>\n<p>App:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10\\Large_Alloc2\\Release&gt;Large_Alloc2.exe <\/p><p>Default process heap found at 0x012B0000 \nPress a key to start...\n<\/p><p>[1] Allocated chunk at 0x012C0FF8 <\/p><p>[2] Allocated chunk at 0x01300FF8 \n[3] Allocated chunk at 0x01340FF8 \n[4] Allocated chunk at 0x015B0048 \n[5] Allocated chunk at 0x015F0048 \n[6] Allocated chunk at 0x01630048 \n[7] Allocated chunk at 0x016B0048 \n[8] Allocated chunk at 0x016F0048 \n[9] Allocated chunk at 0x01730048 \n[10] Allocated chunk at 0x01770048 \n[11] Allocated chunk at 0x017B0048 \n[12] Allocated chunk at 0x017F0048 \n[13] Allocated chunk at 0x01830048 \n[14] Allocated chunk at 0x018B0048 \n[15] Allocated chunk at 0x018F0048 \n[16] Allocated chunk at 0x01930048 \n[17] Allocated chunk at 0x01970048 \n[18] Allocated chunk at 0x019B0048 \n[19] Allocated chunk at 0x019F0048 \n[20] Allocated chunk at 0x01A30048 \n[21] Allocated chunk at 0x01A70048 \n[22] Allocated chunk at 0x01AB0048\n<\/p><p>...<\/p><\/pre>\n<p>WinDBG:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; d 0c0c0c0c <\/p><p>0c0c0c0c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA \n0c0c0c1c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA \n0c0c0c2c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA \n0c0c0c3c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA \n0c0c0c4c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA \n0c0c0c5c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA \n0c0c0c6c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA \n0c0c0c7c 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA<\/p><\/pre>\n<p>To turn this into a precise heap spray, we need to overcome the fact that we don't know the exact start address of the first one.&#160; As we know that the start addresses will be aligned eventually to the start of a page, and we can control the size of the allocations, we simply have to repeat the same structure&#160; (junk + ROP + shellcode + junk) every 0x1000 bytes inside each allocation (as explained in the heap spray tutorials on this site). This should allow you to put\/find your content at a predictable address.&#160; The same logic applies if you need to put specific values at specific places... simply repeat the layout every 0x1000 bytes and you should be fine.<\/p>\n<p>In &quot;Precise_Spray&quot;, the goal is to put marker &quot;$$$$&quot; (\\x24\\x24\\x24\\x24) at&#160; 0x0c0c0c0c:<\/p>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>C:\\Users\\corelan\\Desktop\\vc++\\win10_heap\\Precise_Spray\\Release&gt;Precise_Spray.exe\nDefault process heap found at 0x00550000\nPress a key to start...<\/p><p>Spray done, check 0x0c0c0c0c\n&gt;&gt; Contents at 0x0c0c0c0c: 24242424<\/p><\/pre>\n<pre style=\"overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; width: 98%; border-bottom: #cecece 1px solid; color: #010101; padding-bottom: 5px; padding-top: 5px; padding-left: 5px; min-height: 40px; border-left: #cecece 1px solid; padding-right: 5px; background-color: #cccccc\"><p>0:003&gt; db 0c0c0c0c\n\n0c0c0c0c&#160; 24 24 24 24 20 20 20 20-20 20 20 20 20 20 20 20&#160; $$$$&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n0c0c0c1c&#160; 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n0c0c0c2c&#160; 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n0c0c0c3c&#160; 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n0c0c0c4c&#160; 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n0c0c0c5c&#160; 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n0c0c0c6c&#160; 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \n0c0c0c7c&#160; 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/p><\/pre>\n<p>Of course, in a complex\/multithreaded application, there will be 'noise' (other allocations and frees) at the same time your heapspray is running, and which could affect the placement of your allocations within the segment.&#160;&#160;&#160; A possible approach could be to cause some large allocations first (50 allocations of 0x1ff00 bytes or so... any big size, smaller than the chunk size you're using for the actual spray), each time followed by a small allocation (which we will keep allocated, to avoid that the big ones get coalesced),&#160; and then free the large ones.&#160; That way, the application can use those freed chunks, split them, consume them, without bothering your aligned spray at all.&#160; <\/p>\n<p>I've had good results with spraying using chunk sizes of 0x20000-8 bytes, and 0x40000-8 bytes, but I guess any similar aligned size that is a multiple of a page size will work.<\/p>\n<p>Good luck y'all.&#160; &lt;3<\/p>\n<p>Peter<\/p>\n<hr \/>\n<p>Oh yeah, before I forget, please check out:<\/p>\n<p><a href=\"https:\/\/facebook.com\/demandglobalchange\">https:\/\/facebook.com\/demandglobalchange<\/a> \/\/ <a title=\"https:\/\/bit.ly\/demandglobalchange_full\" href=\"https:\/\/bit.ly\/demandglobalchange_full\">https:\/\/bit.ly\/demandglobalchange_full<\/a> \/\/ <a href=\"https:\/\/bit.ly\/demandglobalchange\">https:\/\/bit.ly\/demandglobalchange<\/a><\/p>\n<p>Read &amp; share. Give people reasons to live, not to die for.&#160; thank you.<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Hi all, Over the course of the past few weeks ago, I received a number of &quot;emergency&quot; calls from some relatives, asking me to look at their computer because &quot;things were broken&quot;, &quot;things looked different&quot; and &quot;I think my computer got hacked&quot;.&#160; I quickly realized that their computers got upgraded to Windows 10. We &hellip; <a href=\"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> \"Windows 10 x86\/wow64 Userland heap\"<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[244,3643],"tags":[3732,3121,2911,2856,2327,955,316,285],"class_list":["post-11044","post","type-post","status-publish","format-standard","hentry","category-exploit-writing-tutorials","category-windows-internals","tag-heap-exploitation","tag-lfh","tag-wow64","tag-spray","tag-breakpoint","tag-c","tag-windows","tag-windbg"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Windows 10 Heap: Userland Analysis for x86\/wow64 Insights<\/title>\n<meta name=\"description\" content=\"Learn how Windows 10 Heap behaves in 32-bit userland, compare with Windows 7, and explore techniques to create predictable heap layouts and sprays.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Windows 10 Heap: Userland Analysis for x86\/wow64 Insights\" \/>\n<meta property=\"og:description\" content=\"Understand Windows 10 userland heap behavior and insights today.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/\" \/>\n<meta property=\"og:site_name\" content=\"Corelan | Exploit Development &amp; Vulnerability Research\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/corelanconsulting\" \/>\n<meta property=\"article:published_time\" content=\"2016-07-05T21:59:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1_thumb.png\" \/>\n<meta name=\"author\" content=\"corelanc0d3r\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Windows 10 Heap: x86\/wow64 Userland Analysis Guide\" \/>\n<meta name=\"twitter:description\" content=\"Learn how the Windows 10 userland heap behaves in 32-bit today.\" \/>\n<meta name=\"twitter:creator\" content=\"@corelanc0d3r\" \/>\n<meta name=\"twitter:site\" content=\"@corelanc0d3r\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/\"},\"author\":{\"name\":\"corelanc0d3r\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/person\\\/3be5542b9b0a0787893db83a5ad68e8f\"},\"headline\":\"Windows 10 x86\\\/wow64 Userland heap\",\"datePublished\":\"2016-07-05T21:59:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/\"},\"wordCount\":6071,\"publisher\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2016\\\/07\\\/heap1_thumb.png\",\"keywords\":[\"heap exploitation\",\"lfh\",\"wow64\",\"heapspray\",\"breakpoint\",\"C#\",\"windows\",\"windbg\"],\"articleSection\":[\"Exploit Writing Tutorials\",\"Windows Internals\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/\",\"name\":\"Windows 10 Heap: Userland Analysis for x86\\\/wow64 Insights\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2016\\\/07\\\/heap1_thumb.png\",\"datePublished\":\"2016-07-05T21:59:38+00:00\",\"description\":\"Learn how Windows 10 Heap behaves in 32-bit userland, compare with Windows 7, and explore techniques to create predictable heap layouts and sprays.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2016\\\/07\\\/heap1_thumb.png\",\"contentUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2016\\\/07\\\/heap1_thumb.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/2016\\\/07\\\/05\\\/windows-10-x86wow64-userland-heap\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.corelan.be\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Windows 10 x86\\\/wow64 Userland heap\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#website\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/\",\"name\":\"Corelan CyberSecurity Research\",\"description\":\"Corelan publishes in-depth tutorials on exploit development, Windows exploitation, vulnerability research, heap internals, reverse engineering and security tooling used by professionals worldwide.\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.corelan.be\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#organization\",\"name\":\"Corelan CyberSecurity Research\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/corelanlogo2_small-20.png\",\"contentUrl\":\"https:\\\/\\\/www.corelan.be\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/corelanlogo2_small-20.png\",\"width\":200,\"height\":200,\"caption\":\"Corelan CyberSecurity Research\"},\"image\":{\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/corelanconsulting\",\"https:\\\/\\\/x.com\\\/corelanc0d3r\",\"https:\\\/\\\/x.com\\\/corelanconsulting\",\"https:\\\/\\\/instagram.com\\\/corelanconsult\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.corelan.be\\\/#\\\/schema\\\/person\\\/3be5542b9b0a0787893db83a5ad68e8f\",\"name\":\"corelanc0d3r\",\"pronouns\":\"he\\\/him\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/3783bed6acd72d7fa5bb2387d88acbb9a3403e7cada60b2037e1cbb74ad451f9?s=96&d=mm&r=x\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/3783bed6acd72d7fa5bb2387d88acbb9a3403e7cada60b2037e1cbb74ad451f9?s=96&d=mm&r=x\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/3783bed6acd72d7fa5bb2387d88acbb9a3403e7cada60b2037e1cbb74ad451f9?s=96&d=mm&r=x\",\"caption\":\"corelanc0d3r\"},\"description\":\"Peter Van Eeckhoutte is the founder of Corelan and a globally recognized expert in exploit development and vulnerability research. With over two decades in IT security, he built Corelan into a respected platform for deep technical research, hands-on training, and knowledge sharing. Known for his influential exploit development tutorials, tools, and real-world training, Peter combines a strong research mindset with a passion for education\u2014helping security professionals understand not just how exploits work, but why.\",\"sameAs\":[\"https:\\\/\\\/www.corelan-training.com\",\"https:\\\/\\\/instagram.com\\\/corelanc0d3r\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/petervaneeckhoutte\\\/\",\"https:\\\/\\\/x.com\\\/corelanc0d3r\"],\"url\":\"https:\\\/\\\/www.corelan.be\\\/index.php\\\/author\\\/admin0\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Windows 10 Heap: Userland Analysis for x86\/wow64 Insights","description":"Learn how Windows 10 Heap behaves in 32-bit userland, compare with Windows 7, and explore techniques to create predictable heap layouts and sprays.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/","og_locale":"en_US","og_type":"article","og_title":"Windows 10 Heap: Userland Analysis for x86\/wow64 Insights","og_description":"Understand Windows 10 userland heap behavior and insights today.","og_url":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/","og_site_name":"Corelan | Exploit Development &amp; Vulnerability Research","article_publisher":"https:\/\/www.facebook.com\/corelanconsulting","article_published_time":"2016-07-05T21:59:38+00:00","og_image":[{"url":"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1_thumb.png","type":"","width":"","height":""}],"author":"corelanc0d3r","twitter_card":"summary_large_image","twitter_title":"Windows 10 Heap: x86\/wow64 Userland Analysis Guide","twitter_description":"Learn how the Windows 10 userland heap behaves in 32-bit today.","twitter_creator":"@corelanc0d3r","twitter_site":"@corelanc0d3r","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/#article","isPartOf":{"@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/"},"author":{"name":"corelanc0d3r","@id":"https:\/\/www.corelan.be\/#\/schema\/person\/3be5542b9b0a0787893db83a5ad68e8f"},"headline":"Windows 10 x86\/wow64 Userland heap","datePublished":"2016-07-05T21:59:38+00:00","mainEntityOfPage":{"@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/"},"wordCount":6071,"publisher":{"@id":"https:\/\/www.corelan.be\/#organization"},"image":{"@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/#primaryimage"},"thumbnailUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1_thumb.png","keywords":["heap exploitation","lfh","wow64","heapspray","breakpoint","C#","windows","windbg"],"articleSection":["Exploit Writing Tutorials","Windows Internals"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/","url":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/","name":"Windows 10 Heap: Userland Analysis for x86\/wow64 Insights","isPartOf":{"@id":"https:\/\/www.corelan.be\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/#primaryimage"},"image":{"@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/#primaryimage"},"thumbnailUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1_thumb.png","datePublished":"2016-07-05T21:59:38+00:00","description":"Learn how Windows 10 Heap behaves in 32-bit userland, compare with Windows 7, and explore techniques to create predictable heap layouts and sprays.","breadcrumb":{"@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/#primaryimage","url":"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1_thumb.png","contentUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2016\/07\/heap1_thumb.png"},{"@type":"BreadcrumbList","@id":"https:\/\/www.corelan.be\/index.php\/2016\/07\/05\/windows-10-x86wow64-userland-heap\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.corelan.be\/"},{"@type":"ListItem","position":2,"name":"Windows 10 x86\/wow64 Userland heap"}]},{"@type":"WebSite","@id":"https:\/\/www.corelan.be\/#website","url":"https:\/\/www.corelan.be\/","name":"Corelan CyberSecurity Research","description":"Corelan publishes in-depth tutorials on exploit development, Windows exploitation, vulnerability research, heap internals, reverse engineering and security tooling used by professionals worldwide.","publisher":{"@id":"https:\/\/www.corelan.be\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.corelan.be\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.corelan.be\/#organization","name":"Corelan CyberSecurity Research","url":"https:\/\/www.corelan.be\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.corelan.be\/#\/schema\/logo\/image\/","url":"https:\/\/www.corelan.be\/wp-content\/uploads\/2026\/03\/corelanlogo2_small-20.png","contentUrl":"https:\/\/www.corelan.be\/wp-content\/uploads\/2026\/03\/corelanlogo2_small-20.png","width":200,"height":200,"caption":"Corelan CyberSecurity Research"},"image":{"@id":"https:\/\/www.corelan.be\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/corelanconsulting","https:\/\/x.com\/corelanc0d3r","https:\/\/x.com\/corelanconsulting","https:\/\/instagram.com\/corelanconsult"]},{"@type":"Person","@id":"https:\/\/www.corelan.be\/#\/schema\/person\/3be5542b9b0a0787893db83a5ad68e8f","name":"corelanc0d3r","pronouns":"he\/him","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/3783bed6acd72d7fa5bb2387d88acbb9a3403e7cada60b2037e1cbb74ad451f9?s=96&d=mm&r=x","url":"https:\/\/secure.gravatar.com\/avatar\/3783bed6acd72d7fa5bb2387d88acbb9a3403e7cada60b2037e1cbb74ad451f9?s=96&d=mm&r=x","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3783bed6acd72d7fa5bb2387d88acbb9a3403e7cada60b2037e1cbb74ad451f9?s=96&d=mm&r=x","caption":"corelanc0d3r"},"description":"Peter Van Eeckhoutte is the founder of Corelan and a globally recognized expert in exploit development and vulnerability research. With over two decades in IT security, he built Corelan into a respected platform for deep technical research, hands-on training, and knowledge sharing. Known for his influential exploit development tutorials, tools, and real-world training, Peter combines a strong research mindset with a passion for education\u2014helping security professionals understand not just how exploits work, but why.","sameAs":["https:\/\/www.corelan-training.com","https:\/\/instagram.com\/corelanc0d3r","https:\/\/www.linkedin.com\/in\/petervaneeckhoutte\/","https:\/\/x.com\/corelanc0d3r"],"url":"https:\/\/www.corelan.be\/index.php\/author\/admin0\/"}]}},"views":44953,"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/posts\/11044","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/comments?post=11044"}],"version-history":[{"count":0,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/posts\/11044\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/media?parent=11044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/categories?post=11044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.corelan.be\/index.php\/wp-json\/wp\/v2\/tags?post=11044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}