- .NET安全攻防指南(上冊)
- 李寅 莫書棋
- 1781字
- 2025-06-11 10:22:30
2.2.2 程序集
通俗來說,我們編寫的C#代碼經過編譯會生成.dll或.exe文件,但這些文件必須在.NET運行時下才能運行,這樣的代碼稱為托管代碼,包含這些托管代碼的二進制單元就是.NET的程序集。盡管.NET的程序集文件與非托管的Windows二進制文件采用相同的文件擴展名(*.dll),但它們的內部完全不同。
1.程序集的組成
每個程序集文件主要由IL代碼、元數據(Metadata)、清單(Manifest)和資源文件組成。其中,IL代碼和元數據會先被編譯為一個或多個托管模塊,然后托管模塊和資源文件會被合并成程序集。
程序集文件中占比最大的一般是IL代碼。IL代碼和Java字節碼相似,它不包含平臺特定的指令,它只在必要的時候被.NET Core運行時中的JIT編譯器編譯成機器碼。
當托管模塊和資源文件合并成程序集時,會生成一份清單,它是專門用來描述程序集本身的元數據。清單包含程序集的當前版本信息、本地化信息,以及正確執行所需的所有外部引用程序集列表等。
2.IL代碼
我們先來看看下面一段簡單的C#代碼被編譯成IL代碼會是什么樣子。

經過編譯后,在項目的bin\Debug目錄下會生成一個與項目名稱同名的dll程序集文件。我們使用ildasm.exe工具打開這個文件,定位到Calculator的Add方法,可以看到Add方法的IL代碼,如圖2-13所示。
這就是IL代碼,如果使用VB或F#編寫相同的Add方法,它生成的IL代碼也是一樣的。由于程序集中的IL代碼不是平臺特定的指令,因此IL代碼必須在使用前調用JIT編譯器進行即時編譯,將其編譯成特定平臺的本地代碼,才能在該平臺運行。
3.程序集清單
.NET Core程序集還包含描述程序集本身的元數據,稱之為清單。清單記錄了當前程序集正常運行所需的所有外部程序集、程序集的版本號、版權信息等。與類型元數據一樣,生成程序集清單也是由編譯器完成的。同樣地,仍以上面Calculator類所在項目為例,在ildasm.exe工具打開的程序集的目錄樹中,雙擊MAINFEST即可查看程序集的清單內容,如圖2-14所示。

圖2-13 IL代碼視圖

圖2-14 IL程序集清單
可以看到,程序集清單首先通過.assembly extern指令記錄了它所引用的外部程序集。接著是當前程序集本身的信息,如版本號、模塊名稱等。
4.私有程序集
.NET私有程序集是指僅在特定應用程序或組件內部使用的程序集,通常不會被部署到全局程序集緩存(Global Assembly Cache,GAC)中,而是隨著應用程序的打包發布部署在文件夾中。比如構建ConsoleJSON.exe可執行文件時,由于內部添加引用了JSON.NET這個開源組件,因此Visual Studio會把Newtonsoft.Json.dll復制到bin目錄下,如圖2-15所示。

圖2-15 bin目錄下的私有程序集dll
私有程序集的優點在于靈活部署,即使不小心移除了私有程序集,也不用擔心會破壞主機上其他應用程序的正常運行。
5.共享程序集
與私有程序集相對的是共享程序集,在大多數情況下,共享程序集安裝在GAC中,而不是部署在應用程序目錄下,程序對它的引用不會產生文件副本。比如經常使用的System.Diagnostics.Process類位于mscorlib.dll程序集,但這個程序集并不會被復制到bin目錄下,因此這個程序集就是一個共享程序集。
(1)GAC
共享程序集安裝在GAC中,GAC的實際位置取決于安裝的.NET版本。在.NET<4.0環境中,GAC安裝在C:\Windows\Assembly目錄下,.NET 4.0發布后,微軟決定將共享程序集隔離到C:\Windows\assembly\GAC_MSIL目錄下,如圖2-16所示。

圖2-16 Windows共享程序集目錄
該目錄下存在很多的子目錄,在每個子目錄下會發現另一個以類似“3.5.0.0__b77a5c561934e089”方式命名的文件,前綴3.5表示由.NET 3.5或更高的版本編譯,兩個下劃線之后的一串像md5哈希的字符串稱為publickey標記,這個公共標記是程序集強名稱的一部分,如圖2-17所示。

圖2-17 查看共享程序集目錄
(2)強名稱
在部署程序集到GAC中之前,必須要賦予它一個強名稱,強名稱是由程序集的標識加上公鑰和數字簽名組成的。強名稱在.NET中的作用好比全局唯一標識符(Globally Unique Identifer,GUID),可以確保唯一性。
我們可以使用Visual Studio創建強名稱,以ConsoleJSON.exe控制臺項目為例,打開項目的屬性頁,選擇“簽名”選項卡,勾選“為程序集簽名”復選框,并在“選擇強名稱密鑰文件”下拉列表中選擇“新建”選項,然后在彈出的對話框中需要指定新的密鑰文件名稱,這里是“dotNetDLLPair.snk”,“簽名算法”默認為sha256RSA,如圖2-18所示。

圖2-18 創建強名稱密鑰
此時在資源管理器中可以看到*.snk文件,每次生成應用程序時都會為這個.dll文件生成一個強名稱,然后在GAC中安裝共享程序集,Visual Studio提供的命令行工具gacutil.exe可以將具有強名稱的程序集添加至GAC中。命令格式為gacutil.exe -i Calculator.dll。注意,只有擁有管理員權限才能與GAC進行交互,如果以普通用戶身份運行,則添加失敗,如圖2-19所示。

圖2-19 普通用戶身份添加程序集緩存失敗
因此以管理員身份運行命令提示符,運行結果如圖2-20所示。

圖2-20 管理員身份添加程序集緩存成功
然后轉到C:\Windows\Microsoft.NET\assembly\GAC_MSIL目錄,會發現包含了一個新的Calculator文件夾,如圖2-21所示。

圖2-21 Calculator已成功添加程序集緩存
(3)加載程序集
.NET查找和加載的程序集方式根據程序集的特征主要分為共享程序集和私有程序集兩種場景。
共享程序集加載順序見表2-13。
表2-13 共享程序集加載順序

私有程序集加載順序見表2-14。
表2-14 私有程序集加載順序

可以看出,通過codeBase和privatePath可以自定義指定程序集加載路徑。下面分別具體介紹<codeBase>和<probing privatePath>,它們是用于配置程序集加載策略的標簽。
1)<codeBase>。
可以在web.config文件的<runtime>元素中使用<codeBase>,對于所有具有強名稱的程序集,要求具有version屬性,但不具有強名稱的程序集應省略。<codeBase>元素要求具有href屬性。在<codeBase>元素中不能指定版本范圍,具體配置請參考下面示例。

2)<probing privatePath>。
默認情況下,.NET應用會嘗試在.exe文件所在的目錄或者bin目錄下搜索程序集文件(.dll),如果引用的外部程序集較多會顯得非常雜亂,因此.NET提供的一種解決方式是向web.config或app.config中添加privatePath屬性,表示搜索私有路徑,這種方式對于大型.NET項目來說非常有用,通常用于配置第三方插件應用。具體配置請參考下面示例。

.NET Web啟動時除了加載bin目錄外,還會從Libs文件夾中加載任意的程序集文件,如果攻擊者可以向此目錄上傳或解壓惡意的程序集文件,可能會觸發RCE(Remote Code Execution,遠程代碼執行)漏洞,因此在代碼審計或者實戰中須關注此配置項。
總的來說,程序集就是.NET Core在編譯后生成的.dll文件,它包含托管模塊、資源文件和程序集清單,其中托管模塊由IL代碼和元數據組成。
需要說明的是,.NET Core與.NET Framework不同,.NET Core始終只會生成.dll格式的程序集文件,即使像控制臺應用這樣的可執行項目也不會生成.exe格式的程序集文件。
那我們在.NET Core項目的bin目錄中看到與項目名稱相同的.exe文件是怎么回事呢?這個文件并不是一個程序集文件,而是專門為Windows平臺生成的一個可執行的快捷方式。在Windows平臺雙擊這個文件等同于執行dotnet <assembly name>.dll命令。在我們安裝的.NET Core目錄中有一個dotnet.exe命令文件(如Windows系統默認位置是C:\Program Files\dotnet\dotnet.exe),在編譯時,該文件會被復制到構建目錄中,并重命名為與項目名稱相同的<assembly name>.exe文件。
- 攻守道:企業數字業務安全風險與防范
- 白話網絡安全2:網安戰略篇
- Metasploit Penetration Testing Cookbook(Third Edition)
- 特種木馬防御與檢測技術研究
- Penetration Testing with Perl
- Web安全與攻防入門很輕松(實戰超值版)
- 網絡安全三十六計:人人該懂的防黑客技巧
- Applied Network Security
- 信息安全案例教程:技術與應用(第2版)
- 計算機網絡安全基礎(第5版)
- 網絡安全設計、配置與管理大全
- 從實踐中學習密碼安全與防護
- Mastering Metasploit
- 復雜信息系統網絡安全體系建設指南
- Instant OSSEC Host-based Intrusion Detection System