WOW64最佳實現(xiàn)

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)上運行的琅锻。

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

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é)束。
使用RegDisableReflectionKeyRegEnableReflectionKey方法可以禁用/啟用反射機制调衰。
該方案只用于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)的影響

  1. 下列程序調(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,所以訪問正常乌妙。

  1. 在下列情況時會出現(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é):

  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)
  • 在調(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位注冊表的訪問;
  1. 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個靖避,如下所示

注意:Wow64EnableWow64FsRedirection在嵌套使用的時候不可靠,所以通常用上面的 Wow64RevertWow64FsRedirection來打開文件系統(tǒng)轉(zhuǎn)向功能比默。

文件與變量的引用

應(yīng)用程序必須確保對文件名與變量(包括系統(tǒng)變量幻捏,環(huán)境變量,系統(tǒng)特殊路徑等)的引用適用于當(dāng)前的操作系統(tǒng)命咐,否則會引起如下問題:

  1. 有些變量只適用于64位操作系統(tǒng)篡九,比如:%ProgramW6432%和FOLDERID_ProgramFilesX64。
  2. 有些變量只適用于32位操作系統(tǒng)醋奠,比如:%windir%\Sysnative瓮下。
  3. 有些變量在不同位數(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)不通用的變量捅位,比如:

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

下面對上述的文件與變量的引用以及文件目錄重定向進(jìn)行簡單總結(jié)轧葛。

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

應(yīng)用程序安裝與啟動

64位操作系統(tǒng)上的應(yīng)用程序分為三種:

  1. 32位應(yīng)用程序
    安裝目錄:C:\Program Files (x86)

  2. 64位應(yīng)用程序
    安裝目錄:C:\Program Files

  3. 雙重版本應(yīng)用程序(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
  • 文件系統(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;  
}  

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. 注冊表重定向
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吝秕,一起剝皮案震驚了整個濱河市泊脐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郭膛,老刑警劉巖晨抡,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異则剃,居然都是意外死亡耘柱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門棍现,熙熙樓的掌柜王于貴愁眉苦臉地迎上來调煎,“玉大人,你說我怎么就攤上這事己肮∈堪溃” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵谎僻,是天一觀的道長娄柳。 經(jīng)常有香客問我,道長艘绍,這世上最難降的妖魔是什么赤拒? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上挎挖,老公的妹妹穿的比我還像新娘这敬。我一直安慰自己,他們只是感情好蕉朵,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布崔涂。 她就那樣靜靜地躺著,像睡著了一般始衅。 火紅的嫁衣襯著肌膚如雪冷蚂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天觅闽,我揣著相機與錄音帝雇,去河邊找鬼。 笑死蛉拙,一個胖子當(dāng)著我的面吹牛尸闸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播孕锄,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼吮廉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了畸肆?” 一聲冷哼從身側(cè)響起宦芦,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎轴脐,沒想到半個月后调卑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡大咱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年恬涧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碴巾。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡溯捆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出厦瓢,到底是詐尸還是另有隱情提揍,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布煮仇,位于F島的核電站劳跃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏浙垫。R本人自食惡果不足惜售碳,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贸人,春花似錦、人聲如沸佃声。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圾亏。三九已至十拣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間志鹃,已是汗流浹背夭问。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留曹铃,地道東北人缰趋。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像陕见,于是被迫代替她去往敵國和親秘血。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理评甜,服務(wù)發(fā)現(xiàn)灰粮,斷路器,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 一忍坷、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡單分配策略的問題地址空間不隔離內(nèi)存使用效率低程序運行的地址不確定 關(guān)于...
    SeanCST閱讀 7,802評論 0 27
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,958評論 6 13
  • 當(dāng)你對自己誠實的時候佩研,世界上沒有人能夠欺騙得了你柑肴。 記不得什么時候起開始不喜歡跟別人一樣,天地之間“我”僅此一個韧骗,...
    哼哼細(xì)語閱讀 302評論 0 0
  • 能執(zhí)行觸摸事件的類有一個共同的特點:都繼承于UIResponder因為UIView和UIViewControlle...
    FallPine閱讀 330評論 0 0