"Even though I walk through the valley of the shadow of death, I will fear no evil..."
On the blog entry "If you are doing your homework correctly..." i showed a little bit how you can modify the LSB of a heap pointer and after freeing it, you can get the heap address on a RtlAllocateHeap call. This is part of Ben Hawkes presentation at RUXCON.
The second step was to construct the overwritting buffer for the Global Heap structure that will allow you to trigger the RtlCommitRutine (which is a function pointer that it triggers when the heap wants to be extended).
To created, you need two hardcoded address (or heap-spray based, or other lovely trick based as sotirov-downd .NET dll load), for the "BlockIndex" and the "UCREntry" else you will suffer for all kind of reading/writing crash in ntdll.dll.
Now, i might be wrong with this statement but on the code flow i follow, the first hardcode address need to fullfilth much more requirements than the one announced by the good old Ben.
There are a couple of ways to allocate on the Vista Heap, which depends on the heap usage (f.e.: The activation of the Low Fragmentation Heap on a given size), argument passed, etc. In our case, to extend it we are gonna allocate without using a Bucket which is the common behaviour.
The BlockIndex is a structure which is saved at [PHEAP+0xB8] and is the first hardcode address we need to craft.
This structure has a single-list which connect other BlockIndex, so our address should have the first Dword as 0x0
*( Blocks + 0) == 0x0
The next dangerous point in code, is when the Block use the FreeListPointer to get a double linked list of chunks out of it.
*( Blocks + 0x18 ) == FLP (FLP needs to be a existing readable addresss)
FLP as I said before, is a double linked list, so the algorythm will take the Backward Link to grab the first chunk out of it.
*(FLP + 4) === CHUNK (CHUNK needs to be readable)
And later, it will take the CHUNK and check the first dword of it and compare it against PHEAP-EncodeFlagMask
*(CHUNK - 8 ) == CONSTANT (if it's zero, its better).
And that it! (he he).
Yes, it doesn't pass the strawberry pudding rule, but as hard as it looks, it's not -that- hard to find address that fullfilth all those requirements. The 2nd hardcode address (UCREntry) requirements are well explained on Ben Hawkes presentation.
I wrote a simple but useful script that try to find addresses that accomplish all those requirements, and believe it or not, there a lot of them.
The question now is: Can we really find one not affected by ASLR?
PS: I don't want to spoil the scoop for the Japanese students on the Heap class, so I will release the script after class ;). (Anyways, you can do it yourself, it's just a couple of readLong).