WOW64最佳实现

WOW64简介

WOW64(Windows 32-bit On Windows 64-bit)是x64平台上运行win32应用程序的模拟器,它在系统层提供了中间层,将win32的系统调用转换成x64进行调用,并且将x64返回的结果转换成win32形式返回给win32程序。下图描述了win32程序如何在x64系统上运行的。

How a 32-bit process runs on 64-bit Windows

WOW64局限性:

  • 地址空间默认是2G,使用/LARGEADDRESSAWARE开关可以达到4G。
  • 32位进程无法加载64位DLL(除了指定的系统DLL)。
  • 不支持16位进程的运行。
  • 无法使用DOS虚拟机(VDM, Vitrual DOS Machine)。
  • Intel安腾系列处理器不支持 AWE, Vectored I/O, PAE 以及DirectX硬件加速API。

注册表机制

众所周知,注册表是windows系统的数据库,系统本身以及安装的程序都依赖注册表。当Windows进化到64位,还要兼容大量的32位应用程序,便碰到了注册表冲突的问题。

注册表树最大可以有512级深度,通过注册表API一次可以创建32级深的键值。

为了解决64位系统的兼容性问题,Windows使用了三套方案,共享(Shared)、注册表重定向(Registry Redirector)和注册表反射(Registry Reflection)。

1. 共享

保存可以被32位和64位共同使用的注册表。

2. 注册表反射

注册表反射是在64位注册表视图和32位注册表视图之间复制某些特定的注册表项和项值。简单的说就是备份和同步,把同一份注册表保存到两个物理位置,分别被32位或64位程序使用。保存发生在RegCloseKey调用结束。
使用RegDisableReflectionKeyRegEnableReflectionKey方法可以禁用/启用反射机制。
该方案只用于Windows Server 2008, Windows Vista, Windows Server 2003 和 Windows XP,从 Windows 7 和 Windows Server 2008 R2 开始被移除

举例:在X64系统中安装64位Microsoft Office后,64位的winword.exe将注册.doc这个扩展名并把这个扩展名关联到winword.exe程序,根据X64的运行机制,64位程序修改的是64位的注册表键值,但是WOW64会自动的把这个修改会同步到32位的注册表键下面,这样32位和64位的应用程序都可以使用64位winword.exe打开.doc文件。

但是,并不是所有的键值都会受到注册表反射机制的影响。实验证明,如果我们使用32位的注册表编辑器在HKEY_LOCAL_MACHINE/Software下新建一个项,然后使用64位的注册表编辑器查看,会发现这个项只会出现在HKEY_LOCAL_MACHINE/Software/Wow6432Node键下而不会出现在HKEY_LOCAL_MACHINE/Software键下,因为HKEY_LOCAL_MACHINE/Software键是专门用于存放64位程序所使用的注册表数据的,而HKEY_LOCAL_MACHINE/Software/Wow6432Node键是专门用于存放32位程序所使用的注册表数据的。

注册表中受到反射机制影响的有:

HKEY_LOCAL_MACHINE/Software/Classes
HKEY_LOCAL_MACHINE/Software/COM3
HKEY_LOCAL_MACHINE/Software/EventSystem
HKEY_LOCAL_MACHINE/Software/Ole
HKEY_LOCAL_MACHINE/Software/Rpc
HKEY_USERS/*/Software/Classes
HKEY_USERS/*_Classes

3. 注册表重定向

注册表重定向为32位和64位程序分别提供不同的注册表物理存储位置,但会映射成同一个逻辑视图,这个过程对程序本身是透明的。也就是说,一个32位程序可以像在32位系统中一样来使用注册表,虽然它们在64位系统上被存储在不同的物理位置。

32位程序重定向的注册表存放在Wow6432Node下,例如, HKEY_LOCAL_MACHINE\Software 会被重定向到 HKEY_LOCAL_MACHINE\Software\Wow6432Node。

需要重定向的注册表项如下所示:

// 64位程序的注册信息存储键
HKLM/Software
HKEY_CLASSES_ROOT 
HKEY_CURRENT_USER/Software/Classes 
HKEY_LOCAL_MACHINE/Software 
HKEY_USERS/*/Software/Classes 
HKEY_USERS/*_Classes
//32位程序的注册信息重定向存储键
HKLM/Software/WOW6432node 
HKEY_CLASSES_ROOT/WOW6432node 
HKEY_CURRENT_USER/Software/Classes/WOW6432node 
HKEY_LOCAL_MACHINE/Software/WOW6432node 
HKEY_USERS/*/Software/Classes/WOW6432node 
HKEY_USERS/*_Classes/WOW6432node

注册表重定向机制对系统的影响

  1. 下列程序调用没有问题:
  • 32位应用程序A调用32位应用程序B并访问B的注册表信息。由于注册表重定向机制,32位应用程序B的注册信息在HKLM/Software/Wow6432Node中,而32位应用程序A访问注册表也会被重定向到HKLM/Software/Wow6432Node中,所以访问正常。

  • 64位应用程序A调用64位应用程序B并访问B的注册表信息。64位应用程序B的注册信息在HKLM/Software,64位应用程序A访问注册表时直接访问HKLM/Software,所以访问正常。

  1. 在下列情况时会出现问题:
  • 64位应用程序调用32位应用程序并访问其注册表信息。因为32位应用程序的注册信息在HKLM/Software/Wow6432Node中,而64位应用程序访问注册表时直接范围HKLM/Software,所以访问异常。

    解决方案:在写注册表时,32位应用程序要将该注册信息写到64位程序的注册表项中,即HKLM/Software下。

  • 32位应用程序调用64位应用程序并访问其注册表信息。同上。

应用程序如何访问注册表

下面对32位与64位应用程序分别访问注册表进行简单总结:

  1. 64位程序如何访问64位的注册表(HKLM/Software)
  • 64位程序访问64位的注册表,直接到 HKLM/Software。
  1. 32位程序如何访问32位的注册表(HKLM/Software/Wow6432Node)
  • 32位程序访问32位的注册表,WOW64将会截取对HKLM/Software访问,并重定向到HKLM/Software/Wow6432Node。
  1. 32位程序如何访问64位的注册表(HKLM/Software)
  • 在调用函数RegCreateKeyEx创建注册表项时,对第六个参数REGSAM samDesired设置中添加参数KEY_WOW64_64KEY,这样可以实现对64位注册表的访问;
  • 在调用函数RegOpenKeyEx打开注册表项时,对第四个参数REGSAM samDesired设置中添加参数KEY_WOW64_64KEY,这样可以实现对64位注册表的访问;
  1. 64位程序如何访问32位的注册表(HKLM/Software/Wow6432Node)
  • 在调用函数RegCreateKeyEx创建注册表项时,对第六个参数REGSAM samDesired设置中添加参数KEY_WOW64_32KEY,这样可以实现对32位注册表的访问;
  • 在调用函数RegOpenKeyEx打开注册表项时,对第四个参数REGSAM samDesired设置中添加参数KEY_WOW64_32KEY,这样可以实现对32位注册表的访问;

文件系统重定向

与注册表类似,系统为了解决文件冲突的问题,引入了文件系统重定向的机制,文件系统重定向使32位程序和64位程序的文件与数据分开存放,%systemroot%/system32 目录被保留给64位文件使用,而32位文件会被重定向到%systemroot%/SysWOW64目录。任何32位程序试图访问%systemroot%/system32 目录都会被重定向到%systemroot%/SysWOW64目录。这是系统默认行为,除非程序的线程明确的指明需要关闭文件系统重定向机制。

文件系统重定向开关

针对%windir%\system32,如果我们用32位程序去访问%windir%\system32,不管我们用硬编码还是其它的方式,系统都会自动地给我们转向到%windir%\syswow64目录。这种转向对于每个32位应用程序默认都是打开的,但是这种转向并不总是需要的。因此,系统提供了相关的API来控制文件重定向的打开与关闭。常用的函数有3个,如下所示

注意:Wow64EnableWow64FsRedirection在嵌套使用的时候不可靠,所以通常用上面的 Wow64RevertWow64FsRedirection来打开文件系统转向功能。

文件与变量的引用

应用程序必须确保对文件名与变量(包括系统变量,环境变量,系统特殊路径等)的引用适用于当前的操作系统,否则会引起如下问题:

  1. 有些变量只适用于64位操作系统,比如:%ProgramW6432%和FOLDERID_ProgramFilesX64。
  2. 有些变量只适用于32位操作系统,比如:%windir%\Sysnative。
  3. 有些变量在不同位数的操作系统下数值不同,比如:%ProgramFiles%和FOLDERID_ProgramFiles。

注意:我们在使用上述变量时必须先判定当前系统的位数信息以确保引用正确。

同理,注册表信息中包含环境变量时也会出现类似问题。比如REG_EXPAND_SZ指向包含环境变量的注册表信息,系统会自动解析键值中包含的%xxx%环境变量。而REG_SZ键值中的%xxx%不会被自动解析。但是可以通过ExpandEnvironmentStrings等系统API进行扩展。当程序调用RegGetValue获取注册表键值的时候,系统会根据当前操作系统的位数信息对环境变量进行扩展,但是应用程序也可以覆盖这种扩展方式。
因此,在64位操作系统中我们要避免使用32位和64位系统不通用的变量,比如:

  1. %ProgramFiles%, FOLDERID_ProgramFiles(CSIDL_PROGRAM_FILES), FOLDERID_ProgramFilesCommon(CSIDL_PROGRAM_FILES_COMMON)
  2. FOLDERID_ProgramFilesX64, FOLDERID_ProgramFilesCommonX64

下面对上述的文件与变量的引用以及文件目录重定向进行简单总结。

Summary of Rules for Referencing Files and Variables
Summary of Defaults for Variables and Paths

应用程序安装与启动

64位操作系统上的应用程序分为三种:

  1. 32位应用程序
    安装目录:C:\Program Files (x86)

  2. 64位应用程序
    安装目录:C:\Program Files

  3. 双重版本应用程序(Dual-bitness application)
    安装目录:参考上述目录
    这种方式必须保证32位版本与64位版本兼容。

Behavior of Applications and Interpreted Files at Process Startup

补充说明:

  • 针对文件重定向,只有32位程序访问64位目录时才会被重定向,例如32位程序访问64位目录C:\Windows\system32;而64位程序则可以直接访问32位目录,不存在重定向,例如64位程序可以直接访问C:\Windows\syswow64
  • 文件系统重定向只是存在system32和systemWOW64的重定向,而不存在program files和ProgramFiles(x86)的重定向一说,直接硬编码绝对路径即可。

获取系统信息代码片段

// 判断应用程序是否运行在X64系统下
BOOL IsX64System()  
{  
    BOOL bIsWow64 = FALSE;  
    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);  
    LPFN_ISWOW64PROCESS pfnIsWow64 = NULL;  
    // 32位系统的kernel32没有IsWow64Process导出函数,直接使用会有问题
    pfnIsWow64 = (LPFN_ISWOW64PROCESS)GetProcAddress(
        GetModuleHandle(_T("kernel32.dll")), "IsWow64Process");  
    if (pfnIsWow64)  
    {  
        if (!pfnIsWow64(GetCurrentProcess(), &bIsWow64))  
        {  
            // handle error  
        }  
    }  
  
    return bIsWow64;  
} 

// 获取系统信息
BOOL GetSystemInfoEx(SYSTEM_INFO *pSystemInfo)  
{  
    BOOL bRet = FALSE;  
    if (!pSystemInfo) 
    {
        goto Exit0;  
    }
    
    typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);  
    PGNSI pfnGNSI = NULL;
    ZeroMemory(pSystemInfo, sizeof(SYSTEM_INFO));  
    if (IsX64System())  
    {  
        // x64下要调用这个API  
        pfnGNSI = (PGNSI)GetProcAddress(  
            GetModuleHandle(_T("kernel32.dll")), "GetNativeSystemInfo");  
        if (!pfnGNSI)
        {       
            goto Exit0;  
        }
        pfnGNSI(pSystemInfo);  
    }  
    else  
    {  
        // 32位系统调用下面的API  
        GetSystemInfo(pSystemInfo);  
    }  
  
    bRet = TRUE;  
Exit0:  
    return bRet;  
}  

Bibliography

  1. Windows Hardware Dev Center Archive
  2. Windows Driver Kit (WDK)
  3. Registry Redirector
  4. Removal of Windows Registry Reflection
  5. File System Redirector
  6. WOW64 Implementation Details
  7. KNOWNFOLDERID
  8. 注册表重定向
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,669评论 0 27
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,499评论 6 13
  • 当你对自己诚实的时候,世界上没有人能够欺骗得了你。 记不得什么时候起开始不喜欢跟别人一样,天地之间“我”仅此一个,...
    哼哼细语阅读 276评论 0 0
  • 能执行触摸事件的类有一个共同的特点:都继承于UIResponder因为UIView和UIViewControlle...
    FallPine阅读 307评论 0 0