Thursday, January 17, 2013

A Real Random VirtualAlloc

In this post i will discuss one disadvantage of using the "VirtualAlloc" function to allocate memory and also suggest a trick to play around this disadvantage.

If you ever used the "VirtualAlloc" function  to allocate memory, you must have noticed that addresses returned are almost the same over instances of the same process. This is due to the "ZwAllocateVirtualMemory" function doing nothing to ensure the randomness of the base address returned, at least in Windows 7.

N.B. VirtualAlloc is just a wrap up of the "VirtualAllocEx" function which is a wrap up of the ntdll "ZwAllocateVirtualMemory" function.

To test that fact, we will create a small application that does almost nothing but calling the "ZwAllocateVirtualMemory" function and printing the base address at which memory has been allocated.
The source code looks like below.

N.B. Even though the ASLR has nothing to do with randomizing the base address of memory returned by ZwAllocateVirtualMemory, we just set the "IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE" bit field for testing purposes.

Compile the above source code and run the application several times. See image below.

As you can see in the image above, the base address is the same (0x30000) across all instances of the process and this poses a security issue.

It seems that Microsoft has taken care of this issue while allocating stack memory for threads. Now in later versions of Windows e.g. Windows 7, the "RtlCreateUserStack" function which is responsible for reserving and committing the memory for threads is calling the "NtSetInformationProcess" function with a new information class to reserve the stack memory at a random address. The new process information class is ProcessThreadStackAllocation 0x29.

Now let's see how this new information class reserves memory.

Looking at the disassembly we can see that the function checks the "StackRandomizationDisabled" flag of the "_EPROCESS" structure. We can also see the function trying to randomize some variable by using the "SystemTime" field of the "SharedUserData" page, and the "RDTSC" instruction.

The function then calls the "MiScanUserAddressSpace" and "ZwAllocateVirtualMemory" functions to reserve memory at a random base address.


Now let's try to test the "ZwSetInformationProcess" function and see if addresses returned are really random. So, we compile the code in the image below and see.
N.B. Setting the "IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE" bit field is necessary for the "StackRandomizationDisabled" bit flag of the "_EPROCESS" structure to be unset.



As you can see in the two images above, in each time we invoked the application we got a random address for the memory allocated.


Conclusion:
using the "ProcessThreadStackAllocation" class of the "ZwSetInformationProcess" function, we can guarantee a random address for memory we allocate which can be considered a security enhancement.

Code and examples for this post can be found here.

You can follow me on Twitter @waleedassar

9 comments:

  1. Windows 8 implements support for randomizing allocations made via VirtualAlloc.

    ReplyDelete
    Replies
    1. Thanks for letting me know. Actually, i got the same response on Twitter.

      https://twitter.com/action_dk/status/292077278039519232

      https://twitter.com/action_dk/status/292078796679544832

      Delete
  2. We covered some of this and also implemented a VirtualAlloc_s function for developers - http://recxltd.blogspot.co.uk/2011/12/introducing-virtualallocs-potentially.html.

    Here is the our original post on VirtualAlloc and ASLR - http://recxltd.blogspot.co.uk/2011/12/curious-case-of-virtualalloc-aslr-and.html

    ReplyDelete
  3. "Brutal Address Space Layout Randomisation" does that for pre-Vista applications, by calling RDTSC to adjust the allocation size of a page, thus subsequent allocations move a bit later in memory.
    It's not very good, but what can you expect from a virus writer. ;-)

    ReplyDelete
  4. I seem to remember that when you call VirtualAlloc you can "suggest" an address instead of passing null. Why not generate a random address and suggest it?

    ReplyDelete
  5. because it's not a suggestion, it's a requirement, so it can fail. Then you might end up in a loop trying lots of addresses until one succeeds.

    ReplyDelete
    Replies
    1. AFAIK it should only fail if the address you requested was already taken. You could pick a random available address then. (Just a theory though, it'd have to be tested).

      Delete
    2. Then it is subject for trial and error. Why bother, if you can ask the kernel to do the randomization job and give you the address while relaxing, no calculations, no loops, etc.

      Delete
  6. "As you can see in the image above, the base address is the same (0x30000) across all instances of the process and this poses a security issue."

    But isn't "IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE" just for the PE loader?

    I thought ASLR on Windows wasn't supposed to randomize all allocations but just the binaries, and only once per boot... glad to hear it's being improved in Windows 8, though :)

    ReplyDelete