WOW64簡介
WOW64(Windows 32-bit On Windows 64-bit)是x64平臺上運行win32應(yīng)用程序的模擬器,它在系統(tǒng)層提供了中間層备绽,將win32的系統(tǒng)調(diào)用轉(zhuǎn)換成x64進(jìn)行調(diào)用,并且將x64返回的結(jié)果轉(zhuǎn)換成win32形式返回給win32程序克饶。下圖描述了win32程序如何在x64系統(tǒng)上運行的琅锻。
WOW64局限性:
- 地址空間默認(rèn)是2G卦停,使用/LARGEADDRESSAWARE開關(guān)可以達(dá)到4G向胡。
- 32位進(jìn)程無法加載64位DLL(除了指定的系統(tǒng)DLL)。
- 不支持16位進(jìn)程的運行惊完。
- 無法使用DOS虛擬機(VDM, Vitrual DOS Machine)僵芹。
- Intel安騰系列處理器不支持 AWE, Vectored I/O, PAE 以及DirectX硬件加速API。
注冊表機制
眾所周知小槐,注冊表是windows系統(tǒng)的數(shù)據(jù)庫拇派,系統(tǒng)本身以及安裝的程序都依賴注冊表。當(dāng)Windows進(jìn)化到64位凿跳,還要兼容大量的32位應(yīng)用程序件豌,便碰到了注冊表沖突的問題。
注冊表樹最大可以有512級深度控嗜,通過注冊表API一次可以創(chuàng)建32級深的鍵值茧彤。
為了解決64位系統(tǒng)的兼容性問題,Windows使用了三套方案疆栏,共享(Shared)曾掂、注冊表重定向(Registry Redirector)和注冊表反射(Registry Reflection)。
1. 共享
保存可以被32位和64位共同使用的注冊表壁顶。
2. 注冊表反射
注冊表反射是在64位注冊表視圖和32位注冊表視圖之間復(fù)制某些特定的注冊表項和項值珠洗。簡單的說就是備份和同步,把同一份注冊表保存到兩個物理位置若专,分別被32位或64位程序使用许蓖。保存發(fā)生在RegCloseKey調(diào)用結(jié)束。
使用RegDisableReflectionKey和RegEnableReflectionKey方法可以禁用/啟用反射機制调衰。
該方案只用于Windows Server 2008, Windows Vista, Windows Server 2003 和 Windows XP蛔糯,從 Windows 7 和 Windows Server 2008 R2 開始被移除。
舉例:在X64系統(tǒng)中安裝64位Microsoft Office后窖式,64位的winword.exe將注冊.doc這個擴(kuò)展名并把這個擴(kuò)展名關(guān)聯(lián)到winword.exe程序,根據(jù)X64的運行機制动壤,64位程序修改的是64位的注冊表鍵值萝喘,但是WOW64會自動的把這個修改會同步到32位的注冊表鍵下面,這樣32位和64位的應(yīng)用程序都可以使用64位winword.exe打開.doc文件琼懊。
但是阁簸,并不是所有的鍵值都會受到注冊表反射機制的影響。實驗證明哼丈,如果我們使用32位的注冊表編輯器在HKEY_LOCAL_MACHINE/Software下新建一個項启妹,然后使用64位的注冊表編輯器查看,會發(fā)現(xiàn)這個項只會出現(xiàn)在HKEY_LOCAL_MACHINE/Software/Wow6432Node鍵下而不會出現(xiàn)在HKEY_LOCAL_MACHINE/Software鍵下醉旦,因為HKEY_LOCAL_MACHINE/Software鍵是專門用于存放64位程序所使用的注冊表數(shù)據(jù)的饶米,而HKEY_LOCAL_MACHINE/Software/Wow6432Node鍵是專門用于存放32位程序所使用的注冊表數(shù)據(jù)的桨啃。
注冊表中受到反射機制影響的有:
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位系統(tǒng)中一樣來使用注冊表丧慈,雖然它們在64位系統(tǒng)上被存儲在不同的物理位置析命。
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
注冊表重定向機制對系統(tǒng)的影響
- 下列程序調(diào)用沒有問題:
32位應(yīng)用程序A調(diào)用32位應(yīng)用程序B并訪問B的注冊表信息鹃愤。由于注冊表重定向機制,32位應(yīng)用程序B的注冊信息在HKLM/Software/Wow6432Node中完域,而32位應(yīng)用程序A訪問注冊表也會被重定向到HKLM/Software/Wow6432Node中软吐,所以訪問正常。
64位應(yīng)用程序A調(diào)用64位應(yīng)用程序B并訪問B的注冊表信息筒主。64位應(yīng)用程序B的注冊信息在HKLM/Software关噪,64位應(yīng)用程序A訪問注冊表時直接訪問HKLM/Software,所以訪問正常乌妙。
- 在下列情況時會出現(xiàn)問題:
-
64位應(yīng)用程序調(diào)用32位應(yīng)用程序并訪問其注冊表信息使兔。因為32位應(yīng)用程序的注冊信息在HKLM/Software/Wow6432Node中,而64位應(yīng)用程序訪問注冊表時直接范圍HKLM/Software藤韵,所以訪問異常虐沥。
解決方案:在寫注冊表時,32位應(yīng)用程序要將該注冊信息寫到64位程序的注冊表項中泽艘,即HKLM/Software下欲险。
32位應(yīng)用程序調(diào)用64位應(yīng)用程序并訪問其注冊表信息。同上匹涮。
應(yīng)用程序如何訪問注冊表
下面對32位與64位應(yīng)用程序分別訪問注冊表進(jìn)行簡單總結(jié):
- 64位程序如何訪問64位的注冊表(HKLM/Software)
- 64位程序訪問64位的注冊表天试,直接到 HKLM/Software。
- 32位程序如何訪問32位的注冊表(HKLM/Software/Wow6432Node)
- 32位程序訪問32位的注冊表然低,WOW64將會截取對HKLM/Software訪問喜每,并重定向到HKLM/Software/Wow6432Node。
- 32位程序如何訪問64位的注冊表(HKLM/Software)
- 在調(diào)用函數(shù)RegCreateKeyEx創(chuàng)建注冊表項時雳攘,對第六個參數(shù)REGSAM samDesired設(shè)置中添加參數(shù)KEY_WOW64_64KEY带兜,這樣可以實現(xiàn)對64位注冊表的訪問;
- 在調(diào)用函數(shù)RegOpenKeyEx打開注冊表項時吨灭,對第四個參數(shù)REGSAM samDesired設(shè)置中添加參數(shù)KEY_WOW64_64KEY刚照,這樣可以實現(xiàn)對64位注冊表的訪問;
- 64位程序如何訪問32位的注冊表(HKLM/Software/Wow6432Node)
- 在調(diào)用函數(shù)RegCreateKeyEx創(chuàng)建注冊表項時喧兄,對第六個參數(shù)REGSAM samDesired設(shè)置中添加參數(shù)KEY_WOW64_32KEY无畔,這樣可以實現(xiàn)對32位注冊表的訪問啊楚;
- 在調(diào)用函數(shù)RegOpenKeyEx打開注冊表項時,對第四個參數(shù)REGSAM samDesired設(shè)置中添加參數(shù)KEY_WOW64_32KEY檩互,這樣可以實現(xiàn)對32位注冊表的訪問特幔;
文件系統(tǒng)重定向
與注冊表類似,系統(tǒng)為了解決文件沖突的問題闸昨,引入了文件系統(tǒng)重定向的機制蚯斯,文件系統(tǒng)重定向使32位程序和64位程序的文件與數(shù)據(jù)分開存放,%systemroot%/system32 目錄被保留給64位文件使用饵较,而32位文件會被重定向到%systemroot%/SysWOW64目錄拍嵌。任何32位程序試圖訪問%systemroot%/system32 目錄都會被重定向到%systemroot%/SysWOW64目錄。這是系統(tǒng)默認(rèn)行為循诉,除非程序的線程明確的指明需要關(guān)閉文件系統(tǒng)重定向機制横辆。
文件系統(tǒng)重定向開關(guān)
針對%windir%\system32,如果我們用32位程序去訪問%windir%\system32茄猫,不管我們用硬編碼還是其它的方式狈蚤,系統(tǒng)都會自動地給我們轉(zhuǎn)向到%windir%\syswow64目錄。這種轉(zhuǎn)向?qū)τ诿總€32位應(yīng)用程序默認(rèn)都是打開的划纽,但是這種轉(zhuǎn)向并不總是需要的脆侮。因此,系統(tǒng)提供了相關(guān)的API來控制文件重定向的打開與關(guān)閉勇劣。常用的函數(shù)有3個靖避,如下所示
- 關(guān)閉系統(tǒng)重定向: Wow64DisableWow64FsRedirection
- 打開系統(tǒng)重定向: Wow64RevertWow64FsRedirection
- 打開系統(tǒng)重定向: Wow64EnableWow64FsRedirection
注意:Wow64EnableWow64FsRedirection在嵌套使用的時候不可靠,所以通常用上面的 Wow64RevertWow64FsRedirection來打開文件系統(tǒng)轉(zhuǎn)向功能比默。
文件與變量的引用
應(yīng)用程序必須確保對文件名與變量(包括系統(tǒng)變量幻捏,環(huán)境變量,系統(tǒng)特殊路徑等)的引用適用于當(dāng)前的操作系統(tǒng)命咐,否則會引起如下問題:
- 有些變量只適用于64位操作系統(tǒng)篡九,比如:%ProgramW6432%和FOLDERID_ProgramFilesX64。
- 有些變量只適用于32位操作系統(tǒng)醋奠,比如:%windir%\Sysnative瓮下。
- 有些變量在不同位數(shù)的操作系統(tǒng)下數(shù)值不同,比如:%ProgramFiles%和FOLDERID_ProgramFiles钝域。
注意:我們在使用上述變量時必須先判定當(dāng)前系統(tǒng)的位數(shù)信息以確保引用正確。
同理锭魔,注冊表信息中包含環(huán)境變量時也會出現(xiàn)類似問題例证。比如REG_EXPAND_SZ指向包含環(huán)境變量的注冊表信息,系統(tǒng)會自動解析鍵值中包含的%xxx%環(huán)境變量迷捧。而REG_SZ鍵值中的%xxx%不會被自動解析织咧。但是可以通過ExpandEnvironmentStrings等系統(tǒng)API進(jìn)行擴(kuò)展胀葱。當(dāng)程序調(diào)用RegGetValue獲取注冊表鍵值的時候,系統(tǒng)會根據(jù)當(dāng)前操作系統(tǒng)的位數(shù)信息對環(huán)境變量進(jìn)行擴(kuò)展笙蒙,但是應(yīng)用程序也可以覆蓋這種擴(kuò)展方式抵屿。
因此,在64位操作系統(tǒng)中我們要避免使用32位和64位系統(tǒng)不通用的變量捅位,比如:
- %ProgramFiles%, FOLDERID_ProgramFiles(CSIDL_PROGRAM_FILES), FOLDERID_ProgramFilesCommon(CSIDL_PROGRAM_FILES_COMMON)
- FOLDERID_ProgramFilesX64, FOLDERID_ProgramFilesCommonX64
下面對上述的文件與變量的引用以及文件目錄重定向進(jìn)行簡單總結(jié)轧葛。
應(yīng)用程序安裝與啟動
64位操作系統(tǒng)上的應(yīng)用程序分為三種:
32位應(yīng)用程序
安裝目錄:C:\Program Files (x86)64位應(yīng)用程序
安裝目錄:C:\Program Files雙重版本應(yīng)用程序(Dual-bitness application)
安裝目錄:參考上述目錄
這種方式必須保證32位版本與64位版本兼容。
補充說明:
- 針對文件重定向艇搀,只有32位程序訪問64位目錄時才會被重定向尿扯,例如32位程序訪問64位目錄C:\Windows\system32;而64位程序則可以直接訪問32位目錄焰雕,不存在重定向衷笋,例如64位程序可以直接訪問C:\Windows\syswow64
- 文件系統(tǒng)重定向只是存在system32和systemWOW64的重定向,而不存在program files和ProgramFiles(x86)的重定向一說矩屁,直接硬編碼絕對路徑即可辟宗。
獲取系統(tǒng)信息代碼片段
// 判斷應(yīng)用程序是否運行在X64系統(tǒng)下
BOOL IsX64System()
{
BOOL bIsWow64 = FALSE;
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
LPFN_ISWOW64PROCESS pfnIsWow64 = NULL;
// 32位系統(tǒng)的kernel32沒有IsWow64Process導(dǎo)出函數(shù),直接使用會有問題
pfnIsWow64 = (LPFN_ISWOW64PROCESS)GetProcAddress(
GetModuleHandle(_T("kernel32.dll")), "IsWow64Process");
if (pfnIsWow64)
{
if (!pfnIsWow64(GetCurrentProcess(), &bIsWow64))
{
// handle error
}
}
return bIsWow64;
}
// 獲取系統(tǒng)信息
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下要調(diào)用這個API
pfnGNSI = (PGNSI)GetProcAddress(
GetModuleHandle(_T("kernel32.dll")), "GetNativeSystemInfo");
if (!pfnGNSI)
{
goto Exit0;
}
pfnGNSI(pSystemInfo);
}
else
{
// 32位系統(tǒng)調(diào)用下面的API
GetSystemInfo(pSystemInfo);
}
bRet = TRUE;
Exit0:
return bRet;
}