WINDOWS 7 GETFILEVERSIONINFOSIZE() CRASH (March 2011)

In February, we received the first report of a crash in Windows Explorer on Windows 7, when a request is made to view the properties of a particular file.

Since then, we have received several more reports of the same crash, including malware files that demonstrate it. That has raised questions about a possible vulnerability, and of course, questions about what's going on.

Of particular interest is the fact that the same action does not cause a crash on Windows XP, which suggests an introduced behaviour. The API that is crashing is GetFileVersionInfoSizeW(), but the root cause is an API far lower in the chain.

And no, it's not exploitable.

When the GetFileVersionInfoSize() function is called for a file, it attempts to load that file into memory, and then parse the resource table to find any version information resource that exists. Customised properties of the file are displayed if the version information is present. The file is loaded into memory using the LoadLibraryExW() function, which in turn calls the LdrGetDllHandle() function on Windows XP, or the LdrGetDllHandleEx() function on Vista, or an internal function within kernelbase.dll in Windows 7. This is the most obvious difference in behaviour.

The LdrGetDllHandleEx() function was introduced in Windows Vista (and its functionality was moved into kernelbase.dll in Windows 7), and as the name implies, it is an extended version of the original function. It accepts an additional parameter which describes exactly how to load the file into memory. Previously, it was not possible using the the LdrGetDllHandle() API to load the file into memory exactly as it would appear when loaded for execution (only the CreateFileMapping() API can do it), without also causing other code to run and thereby possibly losing control of the load. The only way to load the file without any risk of code execution was to load the file into memory exactly as it appears on disk.

Now, with the LdrGetDllHandleEx() function, there is a flag that tells Windows to load it exactly as it would appear when loaded for execution, but without resolving imports and thus without any risk of executing code..

Conveniently, there is also an undocumented flag in an undocumented field of a well-known structure, to retain the "legacy" behaviour of loading the file into memory only exactly as it appears on disk. The existence of this undocumented-ness introduces a problem for any anti-malware engine that emulates Windows Vista or later, since if the engine does not support the undocumented behaviour, it can be detected and evaded.

Getting back to the crash, if the file loaded into memory exactly as it would appear when loaded for execution, that includes the honoring of section attributes. If a section does not have any attributes set, then that region of memory will not only have no content, it will not even be mapped in. As a result, if a data structure elsewhere in the file (for example, a version information resource) points into such a region, then the API that is performs the access will crash. This is exactly what happens with the GetFileVersionInfoSize() API. The file has a section with no attributes set and a version resource that points into it. The file is compressed, and the act of decompression will cause content to be placed into that region, which is how the file can execute correctly, even though the properties cannot be accessed from outside (in fact, it is possible to craft a file such that by simply highlighting it, without even requesting the properties, will cause a crash).

Since no user-defined code can execute while the API is attempting to retrieve the properties, the crash is harmless but annoying.

So there we have it.