WOW64 Rant

An opinionated but technical walk through WOW64, compatibility surface area, and what happens when you try to remove it.

[tl;dr]

Foreword

This one has been in the works for a while as a sort of… side effect from other efforts. Apart from ranting, we’ll be digging into some technicals as well and writing some code - feel free to follow along! :)

Background

I’m going to try and keep this part short as there are already a ton of excellent resources on WOW64, heaven’s gate, et. al. - I’ll put a dump of links at the bottom though if you want to look at all the stuff I was looking at.

Skip this section if you don’t care about the nerdy stuff.

– WARNING: super_nerdy_stuff

Microsoft has had the monumental task of attempting to maintain a semblance of software compatibility within their flagship OSes over the past 3 decades or so.

The 90s (16/32 -> 32 bit)

In the early 9x days, Windows booted on top of MSDOS - that is, Win9x actually contained and required a copy of the DOS kernel within MSDOS.SYS… this was kind of a common chain loading process in those days.

The 9x kernels weren’t the only effort going on, however. At the same time, Microsoft was developing a separate, 32bit only, kernel branch dubbed “New Technology” or NT.

So… this created a massive problem right out of the gate as MSDOS binaries could be 16bit as well and require direct hardware access and other “real-mode” stuff that NT was designed to distance itself from.

Enter NTVDM or NT Virtual DOS Machine which has been around about the same amount of time. This emulation layer was driver supported and the complexity of how it all works is beyond our current scope. In fact, NTVDM is still supported on 32 bit editions of Windows 10. Why not 64bit? We’ll touch on that later.

The Mid -> Late 00’s (32->64 bit)

The transition from 32 to 64 bit Operating systems, for those of us who remember, calling the transition “ungraceful” would be a pretty nice way to put it (lol).

Confusion surrounded Windows XP 64 bit Edition or x64 Edition, Itaniums, AMD64, Intel eventually getting into 64 bit architecture, etc… and it has kind of been a mess ever since at least in the Windows world.

The traditional 32bit Windows OS (we’ll just call it IA32 NT for now) was a massively complex beast - to say “far more complicated than DOS” would probably be one the biggest understatements in existence.

Further, it didn’t live inside of a host process like how NTVDM spawned its emulated environment through COMMAND.COM, there was a lot more that had to be done in terms of building a subsystem to support IA32 NT stuff. For this, a far more complicated and robust compatibility layer had to be created.

Enter Windows On Windows 64 (WOW64)

With x64 editions of Windows, Microsoft took an expanded and considerably more complicated direction from how they approached NTVDM - this is pretty much ignoring the fact that kernel level code such as drivers would have to be ported as no real compatibility layer would help here.

In fact, this is a rather sizable reason for the lack of NTVDM on x64 versions of Windows. Other than the fact that NTVDM relies on components that WOW64 has to emulate, NTVDM also required drivers that don’t exist for x64 builds for one reason or another.

Some Design Changes

Under the Hood

To fully explain what happens after you execute a 32bit process on 64bit Windows would take a bit, but here’s the gist:

Note: It’s important to keep in mind that a process on 64bit Windows always is and will be, a 64 bit process at its core.

Process Creation

It should be noted that, at this point, the collection of 64 bit libraries still exists in memory, albeit in non addressable regions to the 32bit process. There are ways to find libraries in 64bit space from a 32bit process but that’s another topic.

Process Runtime

Like the Linux world, for Windows, a lot of… stuff ends up happening with a process via syscalls. Eventually, your library calls will boil down to more and more granular requests to the kernel dealing with stuff like:

The list goes on - read the syscall list if you’re interested :)

In a lot of cases, following a low level call chain will end up in a system library (kernel32, user32, etc) and eventually end up in ntdll as sort of a “last stop” before kernel space.

Even a custom piece of hardware with its own driver will eventually touch ntdll for a request to talk to the hardware.

A Native 64bit ntdll function will perform a syscall to the kernel: x64_syscall

By replacing the 32bit ntdll with a stub library and helpers in 64bit space (those wow64 libraries), Microsoft has created a sort of… proxy which can take syscall requests from a legacy 32bit application, jump to a known address in wow64.dll, convert the pointers, jump to 64bit space, make a 64bit syscall (through our 64bit dll), and return a proper result in 32bit space:

wow64_syscall

It should be noted that this does come with a noticeable performance penalty.

Back in the day **shakes cane**, it made sense to run demanding 32bit software on a 32bit OS as benchmarks were often higher due to the lack of this translation. These days, however, those performance deltas have become less of an issue and, arguably with the advent of multithreading, better 64bit drivers, and other factors, it’s hard to say if the majority of cases still have that same result.

In fact, this “High Level Emulation” for those familiar with the emulation scene is a key component of how more sophisticated emulators work as a lot of modern consoles have entire OSes that need to operate with their own internal states and dispatch calls. An example that demonstrates this the most intuitively within Windows might be CXBX-Reloaded [https://github.com/Cxbx-Reloaded/Cxbx-Reloaded] where XBOX calls are translated to modern functions and eventually native syscalls.

In many cases, some of the more basic syscalls can be directly mapped to syscalls in the host OS, where some have to be patched and adjusted or fully emulated if there isn’t a parallel.

– END super_nerdy_stuff

The Present

WOW64 Today

The WOW64 subsystem is still a standard feature within Windows 10. For a long while, core OS utilities and services for both Windows Server and Consumer builds were 32bit only.

If it ain’t broke, don’t fix it?

If this subsystem offers greater compatibility and additional features, why remove it? A few reasons:

Experiment - Blocking WOW64 execution

Let’s see what a world would be like if Windows let us disable WOW64…

There are a few ways to test this, but a relatively quick way is to copy a 64bit library with the name “wow64log.dll” to our SYSTEM32 directory. We’ll do something fairly basic and either not link against anything or link against ntdll to close the application once WOW64 is force loaded, something like the following:

// Compile (64bit) as "wow64log.dll" and place in SYSTEM32.
#include <libloaderapi.h>
#define EXPORTABLE __declspec(dllexport)
#define NAKED __declspec(naked)
#define NTAPI __stdcall
#define WINAPI __stdcall

#define STATUS_SUCCESS 0

typedef long NTSTATUS;
typedef int BOOL;


EXPORTABLE NTSTATUS NTAPI Wow64LogInitialize(void){return STATUS_SUCCESS;}
EXPORTABLE NTSTATUS NTAPI Wow64LogMessageArgList(unsigned char Level,const char* Format,void* Args) { return STATUS_SUCCESS; }
EXPORTABLE NTSTATUS NTAPI Wow64LogSystemService(void* ServiceParameters) { return STATUS_SUCCESS; }
EXPORTABLE NTSTATUS NTAPI Wow64LogTerminate(void) { return STATUS_SUCCESS; }


BOOL WINAPI DllMain(void* hinstDLL, unsigned int fdwReason, void* lpvReserved) {
    // The exit code doesn't matter as there's nothing loaded
    // yet to set an error or return value.
    exit(0);
}

Note 1: The exports for this library are required - although I guess if we’re killing the process on bind, that probably doesn’t matter.

Note 2: The example above is a bit different from the repository version [https://github.com/batteryshark/stfuWOW64/blob/master/src/stfuwow64.c] as it does not make the exit syscall directly, and instead asks the 64bit ntdll to do it which will aid compatibility.

Note 3: I was going to include a precompiled copy of the library, but you should never trust strangers on the Internet asking to stick dlls into SYSTEM32.

Placing the wow64log.dll library in SYSTEM32 should not have any immediate effects. After all, wow64log is only dynamically loaded on process creation, but feel free to try and execute C:\Windows\SysWow64\notepad.exe and watch it not start.

On Windows 7

Removing WOW64 subsystem components from Windows7 will break several items:

Win7Error

On Windows 10

Microsoft has made some serious strides (probably partially due to UWP/OneCore) in getting away from the older 32bit system utilities.

We can take this a step beyond as well by ripping out two major WOW64 parts, the WOW64 system directory and “Program Files (x86)” directory.

While this is entirely possible, it may be difficult to do so due to permissions and external ‘unlocker’ tools might have to be used alongside several reboots. In the end though, it would look something like this:

Root without WOW64 - ignore my msys64

Now… what breaks with Windows 10 when WOW64 is missing? By default, nothing at first. Some notes, however:

On Windows Server

Around Windows Server 2008, Microsoft decided to allow removal of WOW64 compatibility with a “Server Core” configuration - essentially removing the role itself. This feature also exists in Server 2016 and 2019:

Root without WOW64

Based on tests, however, it does not remove ones ability to run 32bit applications and is somewhat of a common question: [https://social.technet.microsoft.com/Forums/office/en-US/f3520ba5-f73c-4acf-ab85-3598d0a7e0cb/simple-32bit-exe-runs-even-after-wow64-feature-is-removed-intended-supported-bug?forum=ws2016].

Instead, it removes some 32bit components on Windows server (presumably to replace them with 64bit components.)

A full list of removed files from Server 2019 is included here.

Summary

Background, tests, and rambling aside, what’s the point here?

The security challenge of compatibility is nothing new. The “battle in the browser” with Flash has been going on for years as more and more issues eventually caused it to become disabled by default and ultimately removed in browsers by 2021.

For security professionals, the writing is on the wall… we can “see the train coming”.

Forget specifics for a second and look at this from an AppSec point of view - you have an ubiquitous legacy component full of duct-tape code with a ton of undocumented workings whose primary environment is unknown to every process that it runs on with a ton of undefined functionality and it can’t be easily disabled or removed. If this was any other system, what would be the responsible mitigation approach?

Things have been somewhat fortunate with WOW64 so far, but we’re probably one serious incident away from having to have a rather rushed and uncomfortable set of conversations.

Let’s start having this conversation now while we have the benefit of being proactive - this wasn’t supposed to be an open letter to colleagues in appsec, reverse engineering, or Microsoft themselves, but let’s talk about this and what we can do before we’re forced to.

Cheers!

July 2019