WOW64 实现详细信息

WOW64 模拟器在用户模式下运行。 它提供 32 位版本的 Ntdll.dll 与处理器内核之间的接口,并截获内核调用。 WOW64 模拟器包含以下 DLL:

  • Wow64.dll 为 Ntoskrnl.exe 入口点函数提供核心仿真基础结构和 thunk。
  • Wow64Win.dll 为 Win32k.sys 入口点函数提供 thunk。
  • (仅 x64) Wow64Cpu.dll 支持在 x64 上运行 x86 程序。
  • (仅限 Intel Itanium)IA32Exec.bin包含 x86 软件模拟器。
  • (仅限 Intel Itanium)Wowia32x.dll 提供IA32Exec.bin和 WOW64 之间的接口。
  • (仅 ARM64) xtajit.dll 包含 x86 软件模拟器。
  • (仅 ARM64) wowarmw.dll 支持在 ARM64 上运行 ARM32 程序。

这些 DLL 以及 64 位版本的 Ntdll.dll是唯一可以加载到 32 位进程的 64 位二进制文件。 在 ARM 上的 Windows 10 上,CHPE(编译的混合可移植可执行文件)二进制文件也可能加载到 x86 32 位进程中。

启动时,Wow64.dll 加载 x86 版本的 Ntdll.dll(或 CHPE 版本(如果已启用),并运行其初始化代码,这将加载所有必要的 32 位 DLL。 几乎所有 32 位 DLL 都是 32 位 Windows 二进制文件的未修改副本,但出于性能原因,有些 DLL 作为 CHPE 加载。 其中一些 DLL 在 WOW64 上的行为与在 32 位 Windows 上的行为不同,通常是因为它们与 64 位系统组件共享内存。 系统保留超过 32 位限制的所有用户模式地址空间。 有关详细信息,请参阅 WOW64 下的性能和内存消耗。

重新生成进行系统调用的 32 位二进制文件,而不是使用 x86 系统服务调用序列。 此调用序列对于 WOW64 来说很便宜,因为它完全处于用户模式。 检测到自定义调用序列后,WOW64 CPU 将转换回本机 64 位模式并调用到 Wow64.dll。 Thunking 在用户模式下完成,以减少对 64 位内核的影响,并降低 thunk 中可能导致内核模式崩溃、数据损坏或安全漏洞的 bug 的风险。 thunk 从 32 位堆栈中提取参数,将其扩展到 64 位,然后进行本机系统调用。

环境变量

当 32 位进程由 64 位进程创建或 64 位进程由 32 位进程创建时,WOW64 会设置所创建进程的环境变量,如下表所示。

过程 环境变量
64 位进程
PROCESSOR_ARCHITECTURE=AMD64 或 PROCESSOR_ARCHITECTURE=IA64 或 PROCESSOR_ARCHITECTURE=ARM64
ProgramFiles=%ProgramFiles%
ProgramW6432=%ProgramFiles%
CommonProgramFiles=%CommonProgramFiles%
CommonProgramW6432=%CommonProgramFiles%
Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP: 从 Windows 7 和 Windows Server 2008 R2 开始添加 ProgramW6432 和 CommonProgramW6432 环境变量。
32 位进程
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=%PROCESSOR_ARCHITECTURE%
ProgramFiles=%ProgramFiles(x86)%
ProgramW6432=%ProgramFiles%
CommonProgramFiles=%CommonProgramFiles(x86)%
CommonProgramW6432=%CommonProgramFiles%

全局挂钩

如果满足以下条件,可以使用 SetWindowsHookEx 函数将 DLL 注入另一个进程:

  • 32 位 DLL 只能注入 32 位进程,64 位 DLL 只能注入 64 位进程。 无法将 32 位 DLL 注入 64 位进程,反之亦然。
  • 32 位和 64 位 DLL 必须具有不同的名称。
  • DLL 和进程的体系结构必须匹配。 例如,不能将 32 位 x86 DLL 注入 32 位 ARM 进程。

有关详细信息,请参阅 SetWindowsHookEx

请注意,WH_MOUSEWH_KEYBOARDWH_JOURNAL*WH_SHELL和低级别挂钩可以在安装挂钩的线程上调用,而不是线程处理挂钩。 对于这些挂钩,如果 32 位挂钩领先于挂钩链中的 64 位挂钩,则调用 32 位和 64 位挂钩。 有关详细信息,请参阅 使用挂钩