The information and source code found in this article is provided strictly for educational purposes only, and without any warranty of any kind. I do not condone anything in this article being used to break any law or to violate any End User Licence Agreement or Terms of Service.
WinVerSpoof is a concept for a console application for Windows XP and newer designed to spoof the Windows product type ('workstation', 'server', or 'domain controller') as seen by a target application.
It appears that in some limited cases, Microsoft has decided to purposefully cripple its own programs so that some program features are unavailable if run under Windows releases of an inappropriate product type. An example of this can be found in the vssadmin command line tool, as discussed in this blog entry, where the author determines (through partially reverse engineering the vssadmin executable file) that vssadmin decides whether or not to remove (or hide) certain functionality based on the Windows product type it's being run on.
Before getting into what WinVerSpoof does, I'd like to outline what the proof of concept code does that was provided in the previously mentioned blog entry. In short, it specifies a launcher that:
The proof of concept code provided in the previously mentioned blog article could easily be expanded to launch any specified executable. However, WinVerSpoof doesn't borrow any code, and actually takes a somewhat different approach to achieve the same desired results. In short, WinVerSpoof is a generic launcher that:
Note: The RtlGetNtProductType function is called by GetVerionExW to populate the wProductType member of the OSVERSIONINFOEX structure.
There are several reasons why my method is not only simpler, but cleaner and a more logical approach to achieving the desired effect in the context of a generic launcher application.
Since we're executing an arbitrary executable that we haven't necessarily had the time to inspect (read as reverse engineer), we can't be sure how exactly the product type is determined. Maybe the target executable uses load-time dynamic linking to call GetVersionEx (through the Import Address Table, as does vssadmin.exe). Or maybe the target uses run-time dynamic linking to locate the address of GetVersionEx (via GetProcAddress). Perhaps the target executable went the more direct route of calling RtlGetNtProductType directly, skipping GetVersionEx entirely. Because of this uncertainty, it's most logical to attempt our tampering at the highest reasonable level. The RtlGetNtProductType function is the highest reasonable level for tampering because:
Besides tampering with the target process at a higher level (and thus increasing chance of success), by directly over-writing the function in the mapped memory of the DLL module, there's no need for DLL injection. This means there's no need to remotely create a new thread in the target process (which is slightly dirty), but even better, doesn't require the even dirtier prospect of loading a new module (DLL) into the target process (which can easily be detectable by the target application, should it care to check). Even though probably not a concern in most cases, it is much easier for an application to detect whether a function it relies on has been relocated or hooked, than to determine that the content (code) of said function is something other than what might be expected.
I'll grant that a lot of these supposed benefits of my method may be—for all practical purposes—unimportant, and that using the methods in the previously mentioned blog entry, users will probably never run into a problem. But the benefits of my method are obtained at no cost, while complexity and resource overhead are (perhaps insignificantly) reduced.
This section was hurridly tacked on for the small percentage of the target audience that might appreciate a peek at things on the lowest level, to help them achieve a more complete understanding of what's going on. I wrote the disassembly annotation some time after I had already done all the real work (had already written the rest of article, as well as the source code for WinVerSpoof). At no point did I actually step through these instructions with a debugger, so there's a chance of error in my interpretations of the disassembly. What follows are the annotated disassemblies of the (32-bit) functions GetVersionExW (kernel32.dll), RtlGetVersion (ntdll.dll), and (partially) RtlGetNtProductType (ntdll.dll), as found on Windows 7 Ultimate 32-bit.
Note that the vast majority of instructions in the RtlGetNtProductType function, which are used to generate a product type if the value was not found in SharedUserData, have been skipped. These instructions are probably not reached in the majority of cases, I find their details of no interest at this time, and they do not impact WinVerSpoof in any way. A very quick glance suggests that the skipped instructions peek into the registry to determine a product type.
For completeness, I've included the NASM-syntax assembler code for my RtlGetNtProductType stub functions