共用方式為


Windows 機密文件已知 DLL 的拉鋸戰

Raymond Chen

Windows 的這一項功能曾經被非正式地稱為「已知 DLL 」(Known DLL),指的是核心模組載入器會以特殊方式處理的動態連結程式庫 (Dynamic Link Library,DLL) 清單。當載入器看到程式有載入時期動態連結至已知 DLL 時,就會立即使用已知的複本,並略過通常在載入模組時的搜尋演算法。有些人可能會認為這屬於安全性功能 (若為如此,也僅是相當弱的安全性功能),但事實上,安全性並非此功能的原意。已知 DLL 完全是為了要提升效能。

已知 DLL 功能的運作方式,已經過多次的演變。在某些 Windows® 版本中,核心會以已知 DLL 做為起點,並查詢已知 DLL 連結的所有 DLL,然後再查詢該些 DLL 所連結的 DLL...以此類推。此程序會針對所有的依存性項目執行一系列的轉移性解析,然後將它們都視為已知。在其他的 Windows 版本中,不會執行此轉移性解析過程;而是僅會將明確列為已知的 DLL 視為已知。在某些 Windows 版本中,已知 DLL 會在系統啟動時由核心預先載入;在其他的版本中,並不會預先載入,所以核心僅會利用清單以省略在路徑中搜尋 DLL 的麻煩。

各個版本不僅對於已知 DLL 的解釋方式會有差異,連 KnownDLL 登錄機碼的內容也有可能變更。Windows 效能小組有時候會變更已知 DLL 清單以及該清單如何轉換成一組 DLL 的規則,一切都根據他們對於應用程式將如何使用 Windows 而異。跟一般的工程設計一樣,都需要取捨和平衡。在系統啟動時預先載入已知 DLL 可以讓使用該些 DLL 的應用程式的啟動速度更快,但是需要付出代價。系統的啟動時間會更久,而且需要佔用更多記憶體,因為該些 DLL 會保留在記憶體中,無論是否有用到它們。整個過程就是個拉鋸戰,以犧牲其他元件的代價來提升某些元件的效能。如何找到最佳平衡點是一項艱難的任務,而且如您所見,此平衡點也持續地在微調,以因應使用模式的演變。

已知 DLL 有一項較不明顯的後果,是已知 DLL 的優先順序會比本機重新導向的 DLL 更高 (我們曾經在 2007 年 1 月的專欄中研討過重新導向的 DLL)。如果您仔細想一想,就能理解此行為是預期的,而非突變的行為。畢竟已知 DLL 的目的,就是要略過搜尋路徑以加快 DLL 的載入速度。如果核心每次都要檢查本機重新導向的 DLL,那只會使執行速度變慢。您可能會想說,在搜尋路徑中加入一個目錄沒什麼大步了,但是如果該目錄位於地球另一端的網路伺服器上,那麼單一個目錄也可能拖累整體效能。

您知道嗎,我們曾經看到需要仰賴特定 DLL 為已知的程式。曾經有一個程式,其應用程式目錄中有一個稱為 Version.dll 的檔案。在正常的規則下,此私用的 Version.dll 檔案應該要覆寫系統目錄中的檔案,但是在 Windows XP 中,Version.dll 已列為已知 DLL。這代表應用程式目錄中的檔案會被忽略,而會優先使用系統目錄中的檔案。

但是在 Windows Vista® 中,Version.dll 以不再列為已知 DLL,這可能是因為效能小組發現應用程式的使用率不高,所以不值得先載入。如此一來,該程式便無法在 Windows Vista 上正常運作,因為該應用程式實際上需要仰賴核心略過該程式在自己的應用程式目錄中所安裝的 DLL。也就是說,該程式主動地在搜尋路徑中安裝了一個 DLL 檔案,但是又需要仰賴 Windows 忽略該檔案!若要 Windows 忽略某個檔案,最有效率的做法當然是一開始就不要安裝該檔案囉。最矛盾的是,負責撰寫該程式的公司竟然提出問題報告,說他們找到一個安全性漏洞。

Raymond Chen 的網站「The Old New Thing」以及採用相同標題做為書名的出版品 (Addison-Wesley,2007),都討論 Windows 的歷史和 Win32 程式設計。他連自己的衣服尺碼都已經不清楚了。

© 2008 Microsoft Corporation and CMP Media, LLC. 保留所有權利;未經允許,嚴禁部分或全部複製.