WoW64: Running 32-bit Processes on 64-bit Windows

Windows Internals
Time it takes to read this article 6 minutes.

Sixteen years after 64-bit Windows became the norm, a large amount of software on any given machine is still 32-bit. Those programs run without modification, seemingly unaware that the operating system and processor around them are 64-bit. The layer that makes this possible is WoW64 — “Windows 32-bit on Windows 64-bit” — a translation subsystem baked into every 64-bit edition of Windows. Understanding how it works is essential for anyone who reverse engineers Windows binaries, writes tooling that has to reason about process bitness, or hunts for malware, because WoW64 is both an everyday compatibility feature and a favorite hiding place for evasion tricks.

Architecture

The key thing to internalize is that there is no 32-bit kernel on 64-bit Windows. The kernel (ntoskrnl.exe), the drivers, and the system call interface are all 64-bit. A 32-bit process is loaded with a 32-bit ntdll.dll and its own 32-bit copies of the core DLLs, but every request it makes must ultimately reach a 64-bit kernel. WoW64 is the user-mode shim that bridges that gap.

WoW64 is implemented as a small set of user-mode DLLs that are loaded into every 32-bit process on a 64-bit system:

  • wow64.dll — the core of the subsystem; it emulates the 64-bit ntdll system-call interface for the 32-bit process and manages the WoW64 environment.
  • wow64cpu.dll — handles the actual CPU mode switching between 32-bit and 64-bit execution.
  • wow64win.dll — thunks the GUI/USER and GDI system calls that go to win32k.sys.

These sit between the process’s 32-bit ntdll and the 64-bit kernel. On x64 hardware the CPU can execute 32-bit code natively in compatibility mode, so WoW64 is a thin thunking layer rather than a full emulator. On ARM64, the same conceptual role is filled by an actual emulation engine (xtajit) that translates x86 — and, on ARM64, x64 — instructions, with WoW64 handling the same system-call and redirection duties around it.

The CPU Mode Switch

An x64 processor distinguishes execution modes by the code segment selector currently loaded in CS. In a WoW64 process, 32-bit code runs in compatibility mode under the segment selector 0x23, while 64-bit code runs in long mode under selector 0x33. Switching between them is done with a far jump or far call that reloads CS with the other selector — there is no expensive kernel transition involved, just a change of the code segment.

This far-jump-to-0x33 technique is popularly known as “Heaven’s Gate.” In legitimate operation it is wow64cpu.dll that performs the switch, flipping the process into 64-bit mode whenever it needs to talk to the kernel and flipping it back afterward. The mechanism itself is simply a documented consequence of how the processor handles mixed-mode segments; it becomes interesting — as we will see — because anyone in the process can perform the same jump, not just WoW64.

System Call Thunking

Follow a single API call to see the whole machine turn. When a 32-bit program calls, say, NtCreateFile, it invokes the stub in its 32-bit ntdll. Instead of issuing a system call directly, that stub transfers control into wow64cpu.dll, which:

  • Performs the Heaven’s Gate switch into 64-bit long mode.
  • Hands off to wow64.dll, which converts the 32-bit arguments into their 64-bit forms — widening pointers and handles, and translating the structures the call expects, since a 64-bit kernel reads 64-bit pointers and layouts.
  • Issues the real syscall instruction with the appropriate system service number, exactly as a native 64-bit process would (see the earlier article on the user-to-kernel transition).

On return, the path runs in reverse: the 64-bit results are marshalled back into 32-bit form, the CPU switches back to compatibility mode, and control returns to the 32-bit ntdll stub as if nothing unusual happened. From the application’s perspective it made an ordinary 32-bit system call; underneath, WoW64 crossed two boundaries — bitness and privilege — to satisfy it.

File System and Registry Redirection

Compatibility is not only about instructions; it is also about paths. A 32-bit program expects its DLLs in C:\Windows\System32, but on 64-bit Windows that directory holds 64-bit binaries, which a 32-bit process cannot load. WoW64 solves this with the File System Redirector: when a 32-bit process accesses C:\Windows\System32, the request is transparently redirected to C:\Windows\SysWOW64, which contains the 32-bit copies of the system DLLs. (The counter-intuitive naming — System32 for 64-bit, SysWOW64 for 32-bit — is a backward-compatibility artifact.)

Sometimes a 32-bit process genuinely needs the real 64-bit System32. For that, Windows provides the Sysnative pseudo-directory: a 32-bit process that references C:\Windows\Sysnative reaches the true 64-bit System32, bypassing redirection. Code can also toggle redirection programmatically with Wow64DisableWow64FsRedirection.

The registry gets similar treatment. To keep 32-bit and 64-bit component registrations from colliding, parts of the registry are redirected for WoW64 processes. A 32-bit process writing to HKLM\Software is silently redirected under HKLM\Software\WOW6432Node, so 32-bit and 64-bit COM registrations, for example, live side by side without overwriting each other. A native 64-bit process sees the un-redirected tree, which is why the same logical key can appear to hold different data depending on the accessing process’s bitness.

Two ntdlls, Two Views

One of the more surprising facts about a WoW64 process is that it has two ntdll.dll images mapped at once: the 32-bit one the application links against, and a 64-bit one that WoW64 itself uses to reach the kernel. The process effectively has a 32-bit view and a 64-bit view layered on the same address space, each with its own environment block. This duality is exactly why debuggers need an explicit way to say which view you want to look at, and why some analysis tools that only understand one view get confused by WoW64 targets.

Inspecting WoW64

You can observe every part of this on a live system. From code or a shell, bitness is queryable; in a debugger, you can switch between the two machine views:

# Is a process running under WoW64? (returns TRUE for 32-bit on 64-bit)
#   IsWow64Process()       - classic check
#   IsWow64Process2()      - also reports the process and native machine arch,
#                            the reliable way to detect x86-on-ARM64

# WinDbg: switch the effective machine between the 32-bit and 64-bit views
0:000> .effmach x86      # see the 32-bit stacks/registers
0:000> .effmach amd64    # see the 64-bit side (WoW64's own ntdll)

# WoW64 debugger extension: switch to the 64-bit context
0:000> !wow64exts.sw

# Compare where a 32-bit vs 64-bit process resolves "System32"
#   32-bit process  ->  C:\Windows\SysWOW64\kernel32.dll
#   64-bit process  ->  C:\Windows\System32\kernel32.dll
#   32-bit via C:\Windows\Sysnative\  ->  real 64-bit System32

IsWow64Process2 is the modern, unambiguous check — it distinguishes a genuinely 32-bit-native machine from x86 emulated on ARM64, which the older IsWow64Process cannot. In WinDbg, .effmach and the !wow64exts extension let you flip between the 32-bit and 64-bit register/stack views of the same thread, which is indispensable when a call stack crosses the WoW64 boundary.

Security Relevance

WoW64’s conveniences are also its abuses, and this is where the internals matter for defenders.

  • Heaven’s Gate evasion. Many user-mode security products hook the 32-bit ntdll stubs to observe a WoW64 process’s system calls. But nothing stops the process itself from performing the far jump to segment 0x33, entering 64-bit mode, and issuing syscalls through the 64-bit ntdll — completely bypassing the 32-bit hooks the monitor installed. Malware has used this “Heaven’s Gate” trick for years to run 64-bit payloads from a 32-bit host and slip past bitness-blind instrumentation.
  • The thunk layer as a chokepoint. Conversely, because every legitimate WoW64 syscall funnels through wow64cpu/wow64.dll, that layer is a natural, harder-to-bypass observation point — which is part of why modern telemetry increasingly sources events from the kernel (ETW Threat Intelligence) rather than from user-mode hooks.
  • Redirection confusion. The System32/SysWOW64 split and WOW6432Node regularly mislead analysts — a file “in System32” or a key “in HKLM\Software” can mean different things depending on process bitness. The same ambiguity enables certain DLL-planting and path-based tricks that rely on which copy of a binary actually gets loaded.

All of this is described for defensive understanding and authorized testing only. The practical takeaway for defenders is to reason about bitness explicitly, prefer kernel-sourced telemetry over 32-bit user-mode hooks, and treat unexpected mode transitions in a 32-bit process as a signal worth investigating.

Conclusion

WoW64 quietly performs a remarkable balancing act: it lets decades-old 32-bit software run unchanged on a 64-bit kernel by thunking system calls, switching CPU modes, and redirecting file-system and registry paths — all in user mode. That same machinery, especially the Heaven’s Gate mode switch, is a recurring theme in evasion, which is exactly why knowing how the legitimate path works is what lets you recognize the illegitimate one. Having crossed the bitness boundary, the next article in the series returns to the kernel’s own memory to examine kernel pool internals — how the executive allocates the structures we have been dissecting all along.

You Might Also Like

This article is part of the Windows Internals series. These related deep-dives cover adjacent parts of the system:

Comments

Copied title and URL