Monday, 20 February 2012

Microsoft KB2639308 - Experiments and Small Print

Microsoft released an interesting hot-fix for Windows 7 and Windows Server 2008 R2 in KB2639308. This patch in the words of Microsoft:
"provides support for the Force ASLR feature. This makes it possible for applications to forcibly relocate images that are not built with the /DYNAMICBASE linker flag. Applications can enable this feature by using new Image File Execution Options (IFEO)."
Recx are currently working on a soon to be released project to assist developers of software installers make use of free OS provided security features. As part of this project we wanted to integrate this functionality into RECXInstallerDefence.h. During our development we had to test that we were creating the registry key correctly and that the patch was installed and working.

We applaud Microsoft for what they're doing, but during our internal testing we stumbled across some small print which we thought we'd share. Our test case was the following:

#include "stdafx.h"
#include 

DWORD Yoink(TCHAR *strFoo, DWORD dwFoo){
 if(dwFoo>10){
  if(rand()%2 == 1){
   fprintf(stdout,"%s\n",strFoo);
  }
 }
 return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
 char strFoo[200];

 fprintf(stdout,"%p %p\n",_tmain,&strFoo);
 if(argc>4){
  Yoink(argv[3],argc);
 }
 
 return 0;
} 
//  <-- this is blogger.com helpfully closing tags!

When then linked it with /DYNAMICBASE:NO and verified with dumpbin.exe:
C:\>dumpbin /headers Foo.exe
...snip..
8100 DLL characteristics
NX compatible
Terminal Server Aware
...snip..
As we can't see Dynamic Base under DLL characteristics we know it's not ASLR enabled. Now an important bit of information in KB2639308 says the binary needs relocations to be present, this can be seen if you set the MitigationOptions value to 0x300:
"Note If the value is set to 0x300, images with stripped relocations will not load."
When we were testing with the value set to 0x100 (try, but load anyway if you can't randomize) we weren't seeing any randomization. So we set the value to 0x300 to ensure that everything was O.K. with our test case.
C:\>reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Foo.exe"
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Foo.exe
MitigationOptions REG_QWORD 0x300
CWDIllegalInDllSearch REG_DWORD 0xffffffff
DisableExceptionChainValidation REG_DWORD 0x0
What did we start seeing?
The system cannot execute the specified program.
This was a little disconcerting so we fired up the Recx time machine and read An In-Depth Look into the Win32 Portable Executable File Format, Part 2 from 2002 which says:
"In Visual C++ 6.0, the linker omits relocations for EXEs when doing a release build. This is because EXEs are the first thing brought into an address space, and therefore are essentially guaranteed to load at the preferred load address. DLLs aren't so lucky, so base relocations should always be left in, unless you have a reason to omit them with the /FIXED switch. In Visual Studio .NET, the linker omits base relocations for debug and release mode EXE files."
Sure enough, looking at our Visual Studio 2010 produced binary, relocations were indeed omitted:  
C:\>dumpbin /all Foo.exe | findstr reloc
0 file pointer to relocation table
0 number of relocations
0 file pointer to relocation table
0 number of relocations
0 file pointer to relocation table
0 number of relocations
0 file pointer to relocation table
0 number of relocations
At this point we should point out that DLLs do include relocations as they may not be guaranteed to load at the same location so may benefit from the patch. To conclude, in our release project we added /FIXED:NO to the linker command line and then verified that relocations were now present:
C:\>dumpbin /all Foo.exe | findstr reloc
0 file pointer to relocation table
0 number of relocations
0 file pointer to relocation table
0 number of relocations
0 file pointer to relocation table
0 number of relocations
0 file pointer to relocation table
0 number of relocations
.reloc name
0 file pointer to relocation table
0 number of relocations
1000 .reloc
Then we executed the binary and it loaded just fine:
C:\>Foo.exe
00011000 0019FE78
Compare this to the same binary but renamed so the Image Execution Options don't take effect:
C:\>Not-Foo.exe
00401000 0018FE78
We see that the binary loads at its requested base address and is thus not randomized when compared to if the forced ASLR option Image Execution Options is used.

Also while Microsoft specifically state there is no minimum entropy the stack appeared at the same location  between executions (but we didn't reboot) which differs from 'proper' ASLR.

So the small print is:
  • Stripped relocations == no ASLR (Microsoft documented this bit).
  • Main program binaries have a very good chance of not having relocations present and thus won't benefit from it even if the DLLs do (Microsoft didn't document this bit).
Our non scientific sample set included the following previously non ASLR enabled Windows binaries:
  • Putty (32bit) - Putty.exe - 0.60.
  • CamStudio (32bit) - camstudio_cl.exe - 2.6b .
  • Apple Software Update (32bit) - SoftwareUpdate.exe - 2.1.3.
  • 7Zip (64bit) - 7z.exe - 9.20.
None of them had relocations present.

1 comment:

  1. I took some time a while back to look around for what did and didn't have relocations. It was fairly common for relocations to be missing. So much so that I suspect a system with 0x300 system-wide won't boot (not tested).

    Thanks for the great post showing the logic behind why so many relocations are missing and how to remedy the situation in future builds!

    ReplyDelete