Windows Internals: Determining WOW64 and if Windows and Processes are 32 bit or 64 bit
Introduction
Here I show how to use the IsWow64Process2
API to determine whether a Windows process is running under WOW64, and whether Windows
and/or the process are 32 bit or 64 bit.
TL; DR;
Let’s dive right in. Below is the completed code.
Code: Here is the Function
Code: Example Usage of the Function
Note: I have verified that the above code works with a 32 bit process running under WOW64, and with a 64 bit process running
natively, both running under 64 bit Windows 10 version 1903 on a 64 bit Intel AMD64 machine.
IsWow64Process2 requirements say IsWow64Process2
minimum support is Windows 10 version 1511 (client),
and Windows Server 2016 (server).
I do not have a 32 bit machine or 32 bit version of Windows to test, nor an ARM or ARM64 machine. Feel free to explore on those platforms and devices.
Discussion
I hope the code is mostly self-explanatory. However, the below discussion breaks it down well to clarify the code.
Function Return Value and Parameters
The three paramaters for the function getBits
are all BOOL
s. The passed arguments will be set to TRUE
or FALSE
after the
appropriate information is extracted in the function. Since the parameters are all reference types, changing them to the appropriate
values in the function changes the values in the original arguments passed in by the caller so the caller can use them. The function
returns a BOOL
which is TRUE
if the function completed successfully, FALSE
otherwise.
Local Variables and Call to IsWow64Process2
Above, we note that two local variables, ProcessMachine
and NativeMachine
, are defined. Their addresses are passed in to IsWow64Process2
and they receive the function’s outputs via the pointer parameters pProcessMachine
and pNativeMachine
, respectively
(see here).
Their names are a bit confusing because of the word Machine in both: these parameters do not necessarily reflect the physical machine architecture
(i.e., the type of physical processor hardware of the machine), but the architecture of the process itself (ProcessMachine
) and the architecture
of the host Windows operating system (NativeMachine
).
ProcessMachine
If ProcessMachine
is IMAGE_FILE_MACHINE_UNKNOWN
(at this time, 0
), the process is not running under WOW64;
it is either 32 bit running natively under 32 bit Windows, or 64 bit running natively underneath 64 bit Windows
(see here).
If it is not IMAGE_FILE_MACHINE_UNKNOWN
, it will be set to a value that reveals the type of the WOW64 process:
see here. There are many different machine type constants, some referring to 64 bit architectures,
and some architectures that are no longer supported by Windows versions that have IsWow64Process2
.
Note this qoute from these docs:
WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows. This allows for 32-bit (x86) Windows applications to run seamlessly in 64-bit (x64) Windows, as well as for 32-bit (x86) and 32-bit (ARM) Windows applications to run seamlessly in 64-bit (ARM64) Windows.
It would appear that the only two possible image file machine constants for a process running under WOW64 returnable via pProcessMachine
are:
IMAGE_FILE_MACHINE_I386
IMAGE_FILE_MACHINE_ARM
These constants would indicate a 32 bit x86 process or a 32 bit ARM process, respectively. Note that an x86 process can run under either an AMD64 or ARM64 WOW64 emulator, but a 32 bit ARM process can only run under an ARM64 WOW64 emulator.
NativeMachine
NativeMachine
will return a value indicating the architecture type of the host Windows operating system
That value is also an image file machine constant. As best I can tell from research, the possible values,
which would be for Windows architectures supporting the IsWow64Process2
API, are:
IMAGE_FILE_MACHINE_I386
(32 bit x86)IMAGE_FILE_MACHINE_ARM
(32 bit ARM)IMAGE_FILE_MACHINE_IA64
(64 bit Intel Itanium)IMAGE_FILE_MACHINE_AMD64
(64 bit Intel or AMD)IMAGE_FILE_MACHINE_ARM64
(64 bit ARM)
I am not sure if the above list is indeed exhaustive. If you know differently, please let me know.
GetCurrentProcess
(see here) returns a pseudo handle to the current process, so the ProcessMachine
information in my
example will reflect the architecture of the current process.
IsWowProcess2 Function Return Value
IsWow64Process2
will return TRUE
if it succeeds, otherwise, FALSE
. If it fails, I display an error indication that includes the
last error code returned by GetLastError
giving the reason for the failure (see here and here). I then return
FALSE
to indicate failure to the caller, in which case the three BOOL
arguments will have undefined values.
Not WOW64 Path
The above code fragment notices the process is not running under WOW64 since IMAGE_FILE_MACHINE_UNKNOWN
is returned (see above).
It immediately sets isWOW64
to FALSE
. The following three paths run under this conditional block:
64 Bit Windows Host Path
If NativeMachine
is any of the possible 64 bit values, indicating the host Windows architecture is 64 bit, I set windowsIs32Bit
and
processIs32Bit
to FALSE
and return success. Since we know Windows is 64 bit, and the process is not running under WOW64,
we know the process is running 64 bit natively on the host OS.
32 Bit Windows Host Path
If NativeMachine
is any of the possible 32 bit values, indicating the host Windows architecture is 32 bit, I set windowsIs32Bit
and
processIs32Bit
to TRUE
and return success. Since we know Windows is 32 bit, we know the process is running 32 bit natively on the host OS.
A 64 bit process cannot run under 32 bit Windows.
Catch All Error Path
If the returned value is not one known by getBits
, I print out an error statement and return failed.
The WOW64 Path
Finally, if ProcessMachine
did not return IMAGE_FILE_MACHINE_UNKNOWN
, the process is running under WOW64. windowsIs32Bit
is set to FALSE
because
WOW64 is only possible under 64 bit Windows, isWow64
is set TRUE
, and processIs32Bit
is set TRUE
because only a 32 bit process
can run under WOW64.
Example Usage
The usage is quite straightforward. In the example, we define the three BOOL
variables to pass as arguments then call the function getBits
to fill them with the appropriate values. If getBits returns FALSE
, we exit the process with a return from main with the value -1
to indicate failure.
Otherwise, we print an appropriate output for each returned BOOL
argument, then return 0 to indicate nominal operation of the process.
Conclusion
IsWow64Process2
provides a nice, new API for its supported Windows versions that returns more information than the old IsWow64Process
(see here). There is no need to fuss about old architectures no longer supported in the latest versions of Windows,
and it is a great way to figure out what the Windows host machine architecture is.
I have written this to provide hopefully robust, working example code of its usage for the community, which I could not find elsewhere. Even though I researched heavily, I am still unsure of some of the details, which I note above, and could not exercise all code paths. However, I feel as is there is great value. Feel free to explore on your own using what I have done as a launching point.
Thanks to Pexels for the free header image.