1.3.2 元數據
元數據是描述數據的數據。在CLR的上下文中,元數據表示由描述符組成的一套體系,這些操作符包括了在一個模塊中被聲明或引用的所有項。由於CLR模型是面向對象的,因此在元數據中描述的項是類和它們的成員,以及它們伴隨著的特性、屬性和關聯。本節簡單地介紹元數據,與原數據安全相關的內容會在後續章節中繼續講解,元數據的詳細內容不在本書的論述范圍之內。
元數據實際上是一塊二進制數據,包含了三種表:定義表、引用表和清單表。
元數據定義表主要是模塊定義、類型定義、方法定義、字段定義、事件定義、參數定義、屬性定義等一系列定義表的集合。當編譯器編譯代碼時,所有定義的內容都會生成對應的定義表。
元數據引用表用於記錄編譯器中源代碼引用的類型、方法、字段、事件。常用的引用表如:AssemblyRef(程序集引用表)、ModuleRef(模塊引用表)、TypeRef(類型引用表)等。
元數據清單表包含了組成程序集所需要的所有信息,同時包含了對其他程序集的引用信息。它明確地指出了哪些條目可以對外開放,哪些條目只可以在程序集內部進行訪問。
下面通過經典的HelloWorld程序簡要分析其中的元數據信息,如代碼清單1-7所示。
代碼清單1-7 HelloWorld程序代碼
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HelloWorld { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.Read(); } } }
下面使用反匯編工具ILDasm打開HelloWorld.exe,雙擊MANIFEST,圖1-7為查看清單信息的截圖。ILDasm的使用方法和參數說明請讀者參考MSDN文檔。
圖1-7 查看程序清單信息
詳細的清單信息如代碼清單1-8所示。
代碼清單1-8 HelloWorld.EXE的清單信息
// Metadata version: v4.0.21006 .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } .assembly HelloWorld { ...... } .hash algorithm 0x00008004 .ver 1:0:0:0 .module HelloWorld.exe // MVID: {B8EB35DD-5AD2-402C-B422-AA63B0AACCFA} .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000003 // ILONLY 32BITREQUIRED // Image base: 0x05C40000
程序比較簡單,代碼中包含了版本、外部引用等簡單的信息。表1-2描述了示例中所使用的 HelloWord.exe 程序集的程序集清單中的各項指令。
表1-2 HelloWorld.exe指令說明
根據程序集的內容,程序集清單可包含許多不同的指令。有關程序集清單中指令的完整列表請讀者參考相關文檔,本例旨在拋磚引玉。若要查看完整的元數據信息,可以使用快捷鍵“Ctlr+M”,如圖1-8所示。
圖1-8 查看元數據信息
1.3.3 IL常用指令
為方便起見,還是以HelloWorld.exe為例講解IL的相關內容。由於篇幅所限,關於IL的詳細內容還請各位讀者參考相關資料。圖1-9為Main方法的IL代碼。
圖1-9 HelloWorld.exe Main方法的IL代碼
在一個中間語言程序中,如果某一行以“.”開始,代表這是一個傳輸給匯編工具的指令;而沒有以“.”開始的行是中間語言的代碼。上圖中.method是方法定義指令,定義了Main方法,參數在“()”中,IL代碼在“{}”中。.entrypoint是入口指令,表明該方法是入口方法。.maxstack指定了最大棧的深度為8。下面的IL_n是代碼標簽,後面是IL代碼。nop是空指令;ldstr指令向棧中壓入字符串“Hello World!”;call指令調用靜態方法Console.WriteLine(string)和Console.read();pop彈出棧頂的值;ret指令表示方法體的結束。IL支持“//”和“/* */”的注釋方法。
提示 在中間語言中,如果需要調用一個方法,需要指定方法的全名,包括它的名稱域(namespace)、類名、返回值類型和參數的數據類型。
表1-3列舉了IL的其他一些常用指令,更多的指令可以查看IL指令表。
表1-3 IL常用指令
查看本欄目
1.3.4 IL與代碼驗證
在將MSIL編譯為本機代碼的過程中,MSIL代碼必須通過驗證過程,除非管理員已經建立了允許代碼跳過驗證的安全策略。驗證過程檢查MSIL和元數據以確定代碼是否是類型安全的,這意味著它僅訪問已被授權訪問的內存位置。類型安全幫助將對象彼此隔離,因而可以保護它們免遭無意或惡意的破壞。它還提供了對代碼可以可靠地強制安全限制的保證。
運行庫使用下列條件來驗證代碼是否為類型安全:
q 對類型的引用與被引用的類型嚴格兼容。
q 在對象上只調用正確定義的操作。
q 標識與聲稱的要求一致。
驗證過程中檢查 MSIL 代碼,嘗試確認該代碼只能通過正確定義的類型訪問內存位置和調用方法。例如,代碼不允許以超出內存范圍的方式來訪問對象。另外,驗證過程檢查代碼以確定 MSIL 是否已正確生成,這是因為不正確的 MSIL 會導致違反類型安全規則。驗證過程通過正確定義的類型安全代碼集,並且它只通過類型安全的代碼。然而,由於驗證過程存在一些限制,某些類型安全代碼可能無法通過驗證,而某些語言在設計上並不產生可驗證的類型安全代碼。如果安全策略要求提供類型安全代碼,而該代碼不能通過驗證,則在運行該代碼時將引發異常。
-------------------------注:本文摘抄自《.NET 安全揭秘》1.3節
作者:玄魂
出處:http://www.cnblogs.com/xuanhun/