3.1 兩種程式集,兩種部署
CLR有兩種程式集,弱命名程式集和強命名程式集,二者基本一樣,區別:強命名程式集時用發行者的公開金鑰/私密金鑰對 進行了簽名,唯一性的標識了程式集的發行者。弱命名程式集只能私人部署,強命名程式集可以使用全域部署,也可以私人部署。
3.2 為程式集指派強式名稱
一個強命名的程式集包括4部分重要屬性,標誌唯一:一個無副檔名的程式集,一個版本號碼,一個語言文化標誌,一個公開金鑰publickey。此外,還使用發行者的私密金鑰進行簽名
MyTypes,Version=1.0.8123.0,Culture=neatral,PublicKeyToken=xxxxxxxxxxxxxxxx(公開金鑰標記)
MS使用公開金鑰/私密金鑰加密技術,這樣,沒有兩家公司有相同的公開金鑰/私密金鑰對(除非他們共用公開金鑰/私密金鑰對)。
使用反射擷取強命名程式集的PublicKeyToken
建立強命名程式集的步驟:
1.產生公開金鑰/私密金鑰對:使用SN命令,這個命令所有開關都區分大小寫
SN -k MyCompany.keys
——這裡MyCompany.keys是建立的檔案名稱
2.將原有程式集升級為強命名程式集
csc /keyfile:MyCompany.keys app.cs
——這裡,app.cs是包含清單表的檔案,不能對不包含清單表的檔案簽名。C#編譯器會開啟MyCompany,使用私密金鑰對程式集進行簽名,並在清單中嵌入公開金鑰。
用私密金鑰簽名一個檔案:是指產生一個強命名程式集時,程式集的FileDef清單中列出了包含的所有本件,將每個檔案名稱添加到清單中,檔案的內容都會根據私密金鑰進行雜湊處理,得到的雜湊值與檔案名稱一起存入FileDef中。這個雜湊值稱為RSA數位簽章。
最終,產生的包含清單的PE32檔案,其中會含有RSA數位簽章和公開金鑰
補充1:簽名預設使用SHA-1演算法,也可以使用別的演算法,通過AL命令的/algid開關指定。
補充2,還可以使用SN命令,在原有基礎上,得到只含公開金鑰的檔案並顯示:
SN -p MyCompany.keys MyCompany.PublicKey
——這裡MyCompany.PublicKey是建立的公開金鑰檔案名稱
SN -pt MyCompany.PublicKey
——顯示公開金鑰與公開金鑰標記
補充3:在IL中,Local對應於Culture
補充4:公開金鑰標記是公開金鑰的最後8個位元組。
AssemblyRef中存的是公開金鑰標記,AssemblyDef存的是公開金鑰。
3.3 GAC 全域組件快取
GAC一般在C:\Windows\Assembly,結構化的,有很多子目錄。
使用Windows Explorer shell擴充來瀏覽GAC目錄,這個工具是在安裝Framework時附帶的。
不能使用手動方法複製組件檔到GAC,要使用GACUtil命令。
只能安裝強命名程式集到GAC中,而且要有Admin/PowerUser許可權。
GAC的好處是可以容納一個程式集的多個版本。每個版本都有自己的目錄。缺點是違反了簡單安裝的原則。
3.4 在產生的程式集中引用一個強命名程式集
第2章有講到,對於不完整路徑,csc編譯時間目錄尋找順序:
1.工作目錄(要編譯的cs檔案所在)
2.系統目錄(csc.exe所在,同時也包括CLR DLL)
3./lib開關指定的目錄
4.LIB系統變數指定的目錄
安裝Framework時,會安裝.NET程式集兩套副本,一套在編譯器/CLR目錄——便於產生程式集,另一套在GAC子目錄——便於在運行時載入它們。編譯時間並不去GAC中尋找。
3.5 強命名程式集能防範篡改
在安裝強命名程式集到GAC時,系統對包含清單的檔案內容進行雜湊處理,並將這個值與PE32檔案中嵌入的RSA數位簽章進行比較,如果一致,就再去比較其他檔案內容(也是雜湊處理在比RSA簽名)。一旦有一個不一致,就不能安裝到GAC。
如果強命名程式集安裝在GAC以外的目錄,則會在載入時比較簽名。
3.6 延遲簽名(部分簽名) delayed signing
開發階段會使用到這個功能
允許開發人員只用公開金鑰來產生一個程式集,而不需要私密金鑰。
編譯時間,會預留一定空間來儲存RSA數位簽章,不對檔案內容進行雜湊處理。CLR會跳過對雜湊值的檢查。以後可以再對其進行簽名。
步驟如下:
1.產生程式集:csc /keyfile: MyCompany.PublicKey /delaysign: MyAssembly.cs
2.跳過對雜湊值的檢查: SN.exe -Vr MyAssembly.dll
3.準備私密金鑰,再次進行簽名: SN.exe -R MyAssembly.dll MyCompany.PrivateKey
4.再次延遲簽名: SN.exe -Vu MyAssembly.dll
3.7 私人部署強命名程式集
強命名程式集如果不在GAC中,每次載入都要進行驗證,有效能損失。
還可以設計為局部共用強命名程式集,指定設定檔的codeBase即可。
3.8 運行庫如何解析類型引用
在TypeRef中尋找類型引用的紀錄,發現其強簽名,然後定位這個程式集的所在位置:會在以下三個地方尋找:
1.同一個檔案:編譯時間就能發現(早期繫結)
2.不同的檔案,但同一個程式集:在FileRef表中
3.不同的檔案,不同的程式集:這時要載入被引用的程式集,從中尋找
註:AssemblyRef使用不帶副檔名的檔案名稱來引用程式集。綁定程式集時,系統通過探測xx.dll和xx.exe來定位檔案。
ModuleDef,ModuleRef,FileDef使用檔案名稱及其副檔名來引用檔案。
註:在GAC中尋找程式集時,除了名稱,版本,語言文化和公開金鑰,還需要CPU體繫結構,而且是先根據這個體繫結構尋找。