2.3 元数据概述
2011-11-21 21:04 iRead 阅读(532) 评论(0) 编辑 收藏 举报现在,我们知道了自己创建的是什么类型的PE文件。但是,Program.exe文件中到底包含什么内容呢?一个托管PE文件由4个部分组成:PE32(+)头,CLR头,元数据以及IL。PE32(+)头是Windows要求的标准信息。CLR头是一个小的信息块,是那些需要CLR的模块(托管模块)所特有的。在这个头中,包含模块在生成所面向的CLR的major(主)和minor(次)版本号;一些标志(flags);一个MethodDef token(稍后详述),它指定了模块的入口方法(前提是该模块是一个CUI或GUI执行体);以及一个可选的强名称数字签名(将在第3章讨论)。最后,CLR头中还包含模块内部的特定元数据的大小和偏移量。可以查看CorHdr.h头文件中定义的IMAGE_COR20_HEADER,了解CLR头的确切格式。
元数据是一个二进制数据块,由几个表构成。这些表分成三个类型:定义表(definition table)、引用表(reference table)和清单表(manifest table)。表2-1总结了模块的元数据块中的一些比较常见的定义表。
表2-1 常用的元数据定义表
元数据定义表名称 | 说明 |
ModuleDef | 总是包含一个用于标识模块的记录项.在这个记录项中,包含模块的文件名和扩展名(但不含路径),以及一个模块版本ID(采用由编译器创建的GUID的形式).这允许自由地重命名文件,同时保留其原始名称记录.然而,我们强烈反对重命名一个文件,它可能妨碍CLR在运行时正确定位程序集 |
TypeDef | 模块中定义的每个类型都在这个定义表中有一个对应的记录项.每个记录项都包含类型的名称、基类型、一些标志(public、private等)以及一些索引,这些索引指向该类型在MethodDef表中拥有的方法、在FieldDef表中拥有的字段、在PropertyDef表中拥有的属性以及在EventDef表中拥有的事件 |
MethodDef | 模块中定义的每个方法都在这个定义表中有一个对应的记录项。每个记录项都包含方法的名称、一些标志(private、public、virtual、abstract、static、final等)、签名以及该方法的IL代码在模块中的偏移量。每个记录项还引用了ParamDef表中的一个记录项,后面包括与方法参数有关的更多信息 |
FieldDef | 模块中定义的每个字段都在这个定义表中有一个对应的记录项。每个记录项都包含标志(private、public等)、类型和名称 |
ParamDef | 模块中定义的每个参数都在这个定义表中有一个对应的记录项。每个记录项都包含标志(in、out、retval等)、类型和名称 |
PropertyDef | 模块中定义的属性都在这个定义表中有一个对应的记录项。每个记录项都包含标志、类型和名称 |
EventDef | 模块中定义的每个事件都在这个定义表中有一个对应的记录项。每个记录项都包含标志和名称 |
编译器编译源代码时,代码定义的任何一样东西都会导致在表2-1列出的某个表中创建一个记录项。编译器还会检测源代码中引用的类型、字段、方法、属性和事件,并创建对应的元数据表记录项。在创建的元数据中,包含一组引用表,它们记录了所引用的内容 。表2-2总结了一些比较常用的引用元数据表。
表2-2 常用的引用元数据表
引用元数据表名称 | 说明 |
AssemblyRef | 模块中引用的每个程序集在这个表中都有一个对应的记录项。每个记录项都包含绑定到程序集所需的信息:程序集名称(不含路径和扩展名)、版本号、语言文化(culture)以及公钥标记(根据发布者的公钥生成的一个小的哈希值,它标识了所引用的程序集的发布者)。在每个记录项中,还包含一些标志(flags)和一个哈希值。这个哈希值本应作为引用的程序集的二进制数据的一个校验和来使用。但是,目前的CLR完全忽略这个哈希值,未来的CLR可能同样如此 |
ModuleRef | 当前模块引用的类型可能是由别的PE模块实现的,所有那些模块在这个表中都有一个对应的记录项。每个记录项都包含模块的文件名和扩展名(不含路径)。在当前的调用程序集中,可能是别的模块实现了你需要的类型,这个表的作用便是建立同那些类型的绑定关系。 |
TypeRef | 模块引用的每个类型在这个表中都有一个对应的记录项。每个记录项都包含类型的名称和一个引用(指向类型的位置)。如果类型是另一个类型中实现的,引用指向的就是一个TypeRef记录项。如果类型是在同一个模块中实现的,引用指向的就是一个ModuleDef记录项。如果类型是在调用程序集内部的另一个模块中实现的,引用指向的就是一个ModuleRef记录项。如果类型是在一个不同的程序集中实现的,引用指向的就是一个AssemblyRef记录项 |
MemberRef | 模块引用的每个成员(字段和方法,以及属性方法和事件方法)都在这个表中有一个对应的记录项。每个记录项都包含成员的名称和签名,并指向对成员进行定义的那个类型的TypeRef记录项 |
除了表2-1和表2-2所列的之外,还有其他许多定义表和引用表。但是,我的目的只是让你体会一下编译器在生成的元数据中调价的各种信息。前面提到还有一组清单(manifest)元数据表,本章稍后会讨论它们。
可用多种工具检查一下托管PE文件中的元数据。我个人喜欢使用ILDasm.exe,即IL Disassembler(IL反汇编器)。要查看元数据表,请执行以下命令行:ILDasm Program.exe
随后会运行ILDasm.exe,并加载Program.exe程序集。要采用一种美观、容易阅读的方式查看元数据,请选择“视图”|“元信息”|“显示!”菜单项(或直接按Ctrl+M组合键)。随后会显示一下信息:
=========================================================== ScopeName : Program.exe MVID : {E97857CE-81C7-4104-885F-0BBC796D0783} =========================================================== Global functions ------------------------------------------------------- Global fields ------------------------------------------------------- Global MemberRefs ------------------------------------------------------- TypeDef #1 (02000002) ------------------------------------------------------- TypDefName: Program (02000002) Flags : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass] [BeforeFieldInit] (00100101) Extends : 01000001 [TypeRef] System.Object Method #1 (06000001) [ENTRYPOINT] ------------------------------------------------------- MethodName: Main (06000001) Flags : [Public] [Static] [HideBySig] [ReuseSlot] (00000096) RVA : 0x00002050 ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT] ReturnType: Void No arguments. Method #2 (06000002) ------------------------------------------------------- MethodName: .ctor (06000002) Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886) RVA : 0x0000205e ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT] hasThis ReturnType: Void No arguments. TypeRef #1 (01000001) ------------------------------------------------------- Token: 0x01000001 ResolutionScope: 0x23000001 TypeRefName: System.Object MemberRef #1 (0a000012) ------------------------------------------------------- Member: (0a000012) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void No arguments. TypeRef #2 (01000002) ------------------------------------------------------- Token: 0x01000002 ResolutionScope: 0x23000001 TypeRefName: System.Runtime.Versioning.TargetFrameworkAttribute MemberRef #1 (0a000001) ------------------------------------------------------- Member: (0a000001) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #3 (01000003) ------------------------------------------------------- Token: 0x01000003 ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyTitleAttribute MemberRef #1 (0a000002) ------------------------------------------------------- Member: (0a000002) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #4 (01000004) ------------------------------------------------------- Token: 0x01000004 ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyDescriptionAttribute MemberRef #1 (0a000003) ------------------------------------------------------- Member: (0a000003) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #5 (01000005) ------------------------------------------------------- Token: 0x01000005 ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyConfigurationAttribute MemberRef #1 (0a000004) ------------------------------------------------------- Member: (0a000004) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #6 (01000006) ------------------------------------------------------- Token: 0x01000006 ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyCompanyAttribute MemberRef #1 (0a000005) ------------------------------------------------------- Member: (0a000005) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #7 (01000007) ------------------------------------------------------- Token: 0x01000007 ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyProductAttribute MemberRef #1 (0a000006) ------------------------------------------------------- Member: (0a000006) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #8 (01000008) ------------------------------------------------------- Token: 0x01000008 ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyCopyrightAttribute MemberRef #1 (0a000007) ------------------------------------------------------- Member: (0a000007) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #9 (01000009) ------------------------------------------------------- Token: 0x01000009 ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyTrademarkAttribute MemberRef #1 (0a000008) ------------------------------------------------------- Member: (0a000008) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #10 (0100000a) ------------------------------------------------------- Token: 0x0100000a ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyCultureAttribute MemberRef #1 (0a000009) ------------------------------------------------------- Member: (0a000009) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #11 (0100000b) ------------------------------------------------------- Token: 0x0100000b ResolutionScope: 0x23000001 TypeRefName: System.Runtime.InteropServices.ComVisibleAttribute MemberRef #1 (0a00000a) ------------------------------------------------------- Member: (0a00000a) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: Boolean TypeRef #12 (0100000c) ------------------------------------------------------- Token: 0x0100000c ResolutionScope: 0x23000001 TypeRefName: System.Runtime.InteropServices.GuidAttribute MemberRef #1 (0a00000b) ------------------------------------------------------- Member: (0a00000b) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #13 (0100000d) ------------------------------------------------------- Token: 0x0100000d ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyVersionAttribute MemberRef #1 (0a00000c) ------------------------------------------------------- Member: (0a00000c) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #14 (0100000e) ------------------------------------------------------- Token: 0x0100000e ResolutionScope: 0x23000001 TypeRefName: System.Reflection.AssemblyFileVersionAttribute MemberRef #1 (0a00000d) ------------------------------------------------------- Member: (0a00000d) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: String TypeRef #15 (0100000f) ------------------------------------------------------- Token: 0x0100000f ResolutionScope: 0x23000001 TypeRefName: System.Diagnostics.DebuggableAttribute MemberRef #1 (0a00000e) ------------------------------------------------------- Member: (0a00000e) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: ValueClass DebuggingModes TypeRef #16 (01000010) ------------------------------------------------------- Token: 0x01000010 ResolutionScope: 0x0100000f TypeRefName: DebuggingModes TypeRef #17 (01000011) ------------------------------------------------------- Token: 0x01000011 ResolutionScope: 0x23000001 TypeRefName: System.Runtime.CompilerServices.CompilationRelaxationsAttribute MemberRef #1 (0a00000f) ------------------------------------------------------- Member: (0a00000f) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void 1 Arguments Argument #1: I4 TypeRef #18 (01000012) ------------------------------------------------------- Token: 0x01000012 ResolutionScope: 0x23000001 TypeRefName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute MemberRef #1 (0a000010) ------------------------------------------------------- Member: (0a000010) .ctor: CallCnvntn: [DEFAULT] hasThis ReturnType: Void No arguments. TypeRef #19 (01000013) ------------------------------------------------------- Token: 0x01000013 ResolutionScope: 0x23000001 TypeRefName: System.Console MemberRef #1 (0a000011) ------------------------------------------------------- Member: (0a000011) WriteLine: CallCnvntn: [DEFAULT] ReturnType: Void 1 Arguments Argument #1: String Assembly ------------------------------------------------------- Token: 0x20000001 Name : Program Public Key : Hash Algorithm : 0x00008004 Version: 1.0.0.0 Major Version: 0x00000001 Minor Version: 0x00000000 Build Number: 0x00000000 Revision Number: 0x00000000 Locale: <null> Flags : [none] (00000000) CustomAttribute #1 (0c000001) ------------------------------------------------------- CustomAttribute Type: 0a000001 CustomAttributeName: System.Runtime.Versioning.TargetFrameworkAttribute :: instance void .ctor(class System.String) Length: 103 Value : 01 00 29 2e 4e 45 54 46 72 61 6d 65 77 6f 72 6b > ).NETFramework< : 2c 56 65 72 73 69 6f 6e 3d 76 34 2e 35 2c 50 72 >,Version=v4.5,Pr< : 6f 66 69 6c 65 3d 43 6c 69 65 6e 74 01 00 54 0e >ofile=Client T < : 14 46 72 61 6d 65 77 6f 72 6b 44 69 73 70 6c 61 > FrameworkDispla< : 79 4e 61 6d 65 21 2e 4e 45 54 20 46 72 61 6d 65 >yName!.NET Frame< : 77 6f 72 6b 20 34 2e 35 20 43 6c 69 65 6e 74 20 >work 4.5 Client < : 50 72 6f 66 69 6c 65 >Profile < ctor args: (".NETFramework,Version=v4.5,Profile=Client") CustomAttribute #2 (0c000002) ------------------------------------------------------- CustomAttribute Type: 0a000002 CustomAttributeName: System.Reflection.AssemblyTitleAttribute :: instance void .ctor(class System.String) Length: 24 Value : 01 00 13 43 6f 6e 73 6f 6c 65 41 70 70 6c 69 63 > ConsoleApplic< : 61 74 69 6f 6e 31 00 00 >ation1 < ctor args: ("ConsoleApplication1") CustomAttribute #3 (0c000003) ------------------------------------------------------- CustomAttribute Type: 0a000003 CustomAttributeName: System.Reflection.AssemblyDescriptionAttribute :: instance void .ctor(class System.String) Length: 5 Value : 01 00 00 00 00 > < ctor args: ("") CustomAttribute #4 (0c000004) ------------------------------------------------------- CustomAttribute Type: 0a000004 CustomAttributeName: System.Reflection.AssemblyConfigurationAttribute :: instance void .ctor(class System.String) Length: 5 Value : 01 00 00 00 00 > < ctor args: ("") CustomAttribute #5 (0c000005) ------------------------------------------------------- CustomAttribute Type: 0a000005 CustomAttributeName: System.Reflection.AssemblyCompanyAttribute :: instance void .ctor(class System.String) Length: 14 Value : 01 00 09 4d 69 63 72 6f 73 6f 66 74 00 00 > Microsoft < ctor args: ("Microsoft") CustomAttribute #6 (0c000006) ------------------------------------------------------- CustomAttribute Type: 0a000006 CustomAttributeName: System.Reflection.AssemblyProductAttribute :: instance void .ctor(class System.String) Length: 24 Value : 01 00 13 43 6f 6e 73 6f 6c 65 41 70 70 6c 69 63 > ConsoleApplic< : 61 74 69 6f 6e 31 00 00 >ation1 < ctor args: ("ConsoleApplication1") CustomAttribute #7 (0c000007) ------------------------------------------------------- CustomAttribute Type: 0a000007 CustomAttributeName: System.Reflection.AssemblyCopyrightAttribute :: instance void .ctor(class System.String) Length: 32 Value : 01 00 1b 43 6f 70 79 72 69 67 68 74 20 c2 a9 20 > Copyright < : 4d 69 63 72 6f 73 6f 66 74 20 32 30 31 31 00 00 >Microsoft 2011 < ctor args: ("Copyright © Microsoft 2011") CustomAttribute #8 (0c000008) ------------------------------------------------------- CustomAttribute Type: 0a000008 CustomAttributeName: System.Reflection.AssemblyTrademarkAttribute :: instance void .ctor(class System.String) Length: 5 Value : 01 00 00 00 00 > < ctor args: ("") CustomAttribute #9 (0c000009) ------------------------------------------------------- CustomAttribute Type: 0a00000a CustomAttributeName: System.Runtime.InteropServices.ComVisibleAttribute :: instance void .ctor(bool) Length: 5 Value : 01 00 00 00 00 > < ctor args: ( <can not decode> ) CustomAttribute #10 (0c00000a) ------------------------------------------------------- CustomAttribute Type: 0a00000b CustomAttributeName: System.Runtime.InteropServices.GuidAttribute :: instance void .ctor(class System.String) Length: 41 Value : 01 00 24 36 64 36 61 62 31 65 39 2d 36 65 31 62 > $6d6ab1e9-6e1b< : 2d 34 66 37 35 2d 38 38 66 61 2d 32 62 33 31 66 >-4f75-88fa-2b31f< : 38 35 35 32 36 35 37 00 00 >8552657 < ctor args: ("6d6ab1e9-6e1b-4f75-88fa-2b31f8552657") CustomAttribute #11 (0c00000b) ------------------------------------------------------- CustomAttribute Type: 0a00000d CustomAttributeName: System.Reflection.AssemblyFileVersionAttribute :: instance void .ctor(class System.String) Length: 12 Value : 01 00 07 31 2e 30 2e 30 2e 30 00 00 > 1.0.0.0 < ctor args: ("1.0.0.0") CustomAttribute #12 (0c00000c) ------------------------------------------------------- CustomAttribute Type: 0a00000e CustomAttributeName: System.Diagnostics.DebuggableAttribute :: instance void .ctor(value class DebuggingModes) Length: 8 Value : 01 00 07 01 00 00 00 00 > < ctor args: ( <can not decode> ) CustomAttribute #13 (0c00000d) ------------------------------------------------------- CustomAttribute Type: 0a00000f CustomAttributeName: System.Runtime.CompilerServices.CompilationRelaxationsAttribute :: instance void .ctor(int32) Length: 8 Value : 01 00 08 00 00 00 00 00 > < ctor args: (8) CustomAttribute #14 (0c00000e) ------------------------------------------------------- CustomAttribute Type: 0a000010 CustomAttributeName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute :: instance void .ctor() Length: 30 Value : 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 > T WrapNonEx< : 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 >ceptionThrows < ctor args: () AssemblyRef #1 (23000001) ------------------------------------------------------- Token: 0x23000001 Public Key or Token: b7 7a 5c 56 19 34 e0 89 Name: mscorlib Version: 4.0.0.0 Major Version: 0x00000004 Minor Version: 0x00000000 Build Number: 0x00000000 Revision Number: 0x00000000 Locale: <null> HashValue Blob: Flags: [none] (00000000) User Strings ------------------------------------------------------- 70000001 : ( 2) L"Hi" Coff symbol name overhead: 0 =========================================================== =========================================================== ===========================================================
幸好,ILDasm成立了元数据表,恰当地合并了一些信息,避免我们去分析原始表的信息。例如,可以看到当ILDasm显示一个TypeDef记录项时,会在第一个TypeRef项之前显示对应的成员定义信息。
你并不需要完全理解这里看到的一切。要注意的重点在于,Program.exe包含一个TypeDef,它的名称是Program。这个类型代表一个public sealed类,这个类是从System.Object派生的(System.Object是引用的另一个程序集中的类型)。Program类型还定义了两个方法:Main和.ctor(一个构造器,或者说constructor)。
Main是一个public static方法,它的代码是IL代码(与之对应的是本地CPU代码,比如x86代码)。Main的返回类型是void,无参数。构造器(名称始终是.ctor)是一个public方法,它的代码也是IL代码。构造器的返回类型是void,无参数,还有一个this指针,指向调用方法时要构造的对象的内存。
强烈建议你练习使用ILDasm。它提供了丰富的信息,而且你对自己看到的东西理解得越多,对CLR及其功能的理解就越好。本书后面会大量地用到ILDasm。
为了增加趣味性,让我们看看关于Program.exe程序集的统计信息。在ILDasm中选择“视图”|“统计”,会显示以下信息:
File size : 4608 PE header size : 512 (496 used) (11.11%) PE additional info : 1655 (35.92%) Num.of PE sections : 3 CLR header size : 72 ( 1.56%) CLR meta-data size : 1568 (34.03%) CLR additional info : 0 ( 0.00%) CLR method headers : 2 ( 0.04%) Managed code : 20 ( 0.43%) Data : 2048 (44.44%) Unaccounted : -1269 (-27.54%) Num.of PE sections : 3 .text - 2048 .rsrc - 1536 .reloc - 512 CLR meta-data size : 1568 Module - 1 (10 bytes) TypeDef - 2 (28 bytes) 0 interfaces, 0 explicit layout TypeRef - 19 (114 bytes) MethodDef - 2 (28 bytes) 0 abstract, 0 native, 2 bodies MemberRef - 18 (108 bytes) CustomAttribute- 14 (84 bytes) Assembly - 1 (22 bytes) AssemblyRef - 1 (20 bytes) Strings - 630 bytes Blobs - 332 bytes UserStrings - 8 bytes Guids - 16 bytes Uncategorized - 168 bytes CLR method headers : 2 Num.of method bodies - 2 Num.of fat headers - 0 Num.of tiny headers - 2 Managed code : 20 Ave method size - 10
从中可以看出文件的大小(字节数)以及构成文件的各个部分的大小(字节数和百分比)。对于这个如此小的Program.exe应用程序,PE头和元数据占据了文件的相当大的一部分。事实上,IL代码只占据了区区20个字节。当然,随着应用程序规模的增大,它会重用它的大多数类型以及对其他类型/程序集的引用,造成元数据和头信息在整个文件中所占的比例逐渐减小。
注意:随便提一句,ILDasm.exe存在一个bug,会影响到它显示的文件长度信息。尤其不要相信Unaccounted信息。