• 浅析.NET Framework对PE文件格式的扩展


    Microsoft .NET Framework出来小阵子了,我也自从其Beta 1以来,第一次接触。本文将从.NET生成的一个小PE文件着手,旨在理解.NET Framework对PE文件格式的扩展。这种扩展目的是让Windows系统识别Common Language Runtime(CLR)。 
       PE文件是Windows系列操作系统的可执行文件格式。本文假设您对这一文件格式有相当的理解,文中未涉及PE在之前的win16及之后的win64上的讨论。在CLR出现之前,PE文件格式仅简单的由PE Header与Native Image(相对于以下介绍的CLR Header与CLR Data部分)组成。Native Image由各个section组成,如.text,.data,.rdate等等,需要指出的是PE文件的这些section名命名规则并不要求一定要以句点开头,事实上这只是Microsoft的对于代码段或数据段的默认说法,像Borland等其他编译器则相应分别命名为CODE,DATA等等。Native Image含有已编译的相应处理器的机器代码。 
       在CLR出现后PE文件扩展出了另外一部分,即CLR Header与CLR Data组成的供.NETFramework运行的支撑部分。CLR Header由.NET Framework SDK的CorHdr.h中的IMAGE_COR20_HEADER结构定义。从CorHdr.h或是IMAGE_COR20_HEADER的命名中Cor的全称Com+ Runtime即可隐隐约约的看到.NET Framework的发展过程,其与COM+的渊源关系了。事实上IMAGE_COR20_HEADER在平台SDK的winnt.h中也有定义,我查阅的了随Windows XP DDK Build 2505发行的winnt.h中Microsoft在给出这个定义时的注释为COM+ 2.0 header structure,而在.NET Framework SDK中即修改为CLR 2.0 header structure了。CLR Data则包含.NET metadata, IL method bodies等等。metadata及IL method是.NET中很关键的术语。IL即Microsoft Intermediate Language的缩写。她是为了.NET跨平台、跨语言的特性而引入的,有其自身的指令集。.NET SDK中的opcode.def列出的其支持的指令集。粗粗看来这些指令集与Intel的X86指令集十分的相像,也是由Prefix指定的的双字节进行编码。 
       下面的我将通过底下列出的这一段C# Console代码来简述C#编译器生成的PE文件的执行流程及PE文件的on disk结构。代只是简单的输出Hi,如下所示: 
       public class App { 
       static public void Main(System.String[] args) { 
       System.Console.WriteLine("Hi"); 
       } 
       } 
       我们简单的使用csc /out:app.exe app.cs对其编译。生成的PE文件,与.NET出现前传统的编译器生成的PE文件一致,也含有IMAGE_DOS_HEADER,我们知道这部分的作用即是早期的DOS在遇到PE文件格式时,能判定这个可执行文件不能执行于DOS下而存在的。IMAGE_DOS_HEADER与将要谈及的一些结构在winnt.h中均有详细定义。Windows OS Loader根据IMAGE_DOS_HEADER中的e_lfanew成员定位紧挨着的IMAGE_NT_HEADERS。其定义如下: 
       typedef struct _IMAGE_NT_HEADERS { 
       DWORD Signature; 
       IMAGE_FILE_HEADER FileHeader; 
       IMAGE_OPTIONAL_HEADER32 OptionalHeader; 
       } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; 
       我们知道IMAGE_OPTIONAL_HEADER32的成员AddressOfEntryPoint 是PE可执行文件的入口,在.NET中其仍为执行入口,这应该是很好理解的。对于一个COMIMAGE_FLAGS_ILONLY(由IMAGE_COR20_HEADER 的成员Flags 指定)的Image,如我们生成的App.exe,这个入口也即间接定位至App.exe的Import表的_CorExeMain函数。_CorExeMain对应EXE文件,由mscoree.dll导出。mscoree.dll位于%WINNT%\system32下,是Microsoft .NET Runtime Execution Engine,应该指出的她是一个Native Image,负责调用IMAGE_COR20_HEADER中的 EntryPointToken 指定的.NET Token。这才是真正IL语言的入口。 
       Native Image部分的各个Section的定位,已经有很多文档介绍,而且winnt.h中都有详细的定义。我只简单的阐述一下: 
       .text、.data等section定位是由IMAGE_OPTIONAL_HEADER32中的DataDirectory成员指定。DataDirectory是一个IMAGE_DATA_DIRECTORY数组,个数为MAGE_NUMBEROF_DIRECTORY_ENTRIES(当前为16)个。各个DataDirectory功能分别由IMAGE_DIRECTORY_ENTRY_***指定,如EXPORT、IMPORT等等。因为IMAGE_DATA_DIRECTORY由VirtualAddress(RVA)与Size组成,所以我们即可以很容易的找到这些Section的位置。与这些Section一样,CLR Header的定位也是DataDirectory指定,其为IMAGE_DIRECTORY_ENTRY_COMHEADER(值为14,.NET Framework SDK V1 CorHdr.h中称谓,在DDK 2505的winnt.h中为IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)。我们生成的App.exe有如下的格式: 
       . 
       . 
       . 
       AddressOfEntryPoint: 0x000022CE (+0x10) 
       . 
       . 
       . 
       DataDirectory[0] - IMAGE_DIRECTORY_ENTRY_EXPORT 
       VirtualAddress: 0x00000000 (+0x60) 
       Size: 0x00000000 (+0x64) 
       DataDirectory[1] - IMAGE_DIRECTORY_ENTRY_IMPORT 
       VirtualAddress: 0x0000227C (+0x68) 
       Size: 0x0000004F (+0x6C) 
       . 
       . 
       . 
       DataDirectory[14] - IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 
       VirtualAddress: 0x00002008 (+0xD0) 
       Size: 0x00000048 (+0xD4) 
       . 
       . 
       . 
       OK,从DataDirectory[14]我们即可以很容易的定位CLR Header。CLR Header可以被合并到其它任何为只读属性的Section中。前面已经提及到CLR Header由IMAGE_COR20_HEADER结构定义。 
       // CLR 2.0 header structure. 
       typedef struct IMAGE_COR20_HEADER 
       { 
       // Header versioning 
       ULONG cb; 
       USHORT MajorRuntimeVersion; 
       USHORT MinorRuntimeVersion; 
       // Symbol table and startup information 
       IMAGE_DATA_DIRECTORY MetaData; 
       ULONG Flags; 
       ULONG EntryPointToken; 
       // Binding information 
       IMAGE_DATA_DIRECTORY Resources; 
       IMAGE_DATA_DIRECTORY StrongNameSignature; 
       // Regular fixup and binding information 
       IMAGE_DATA_DIRECTORY CodeManagerTable; 
       IMAGE_DATA_DIRECTORY VTableFixups; 
       IMAGE_DATA_DIRECTORY ExportAddressTableJumps; 
       // Precompiled image info (internal use only - set to zero) 
       IMAGE_DATA_DIRECTORY ManagedNativeHeader; 
       } IMAGE_COR20_HEADER; 
       这个结构的Flags与EntryPointToken上面已经提及。从这么多的IMAGE_DATA_DIRECTORY上看,这个定义很像IMAGE_OPTIONAL_HEADER32,后者可以理解成PE文件头的精华,其用于定位.text等Section,由Windows OS Loader执行。而前者用于定位.NET CLR Data,如MetaData、Resources、StrongNameSignature等等。不同的是IMAGE_COR20_HEADER是由mscoree.dll中的_CorExeMain(对应于EXE文件)负责调用(MSIL语言需经过JIT编译成机器码才可执行)。 
       虽然EnrtyPointToken与上面的AddressOfEntryPoint均是执行入口,但却有非常大的区别。AddressOfEntryPoint是一RVA,直接指向执行地址(相对于Image Base),其只能指向一本地机器代码用于装载NET Runtime(如mscoree.dll中的_CorExeMain,对于DLL文件其可以置为0)。而EntryPointToken只是一个.NET TOKEN。TOKEN是.NET Type的唯一识别,是一个DWORD值。其最高的8bit指明何种TOKEN。其由CorHdr.h中的CorTokenType enum定义。如mdtMethodDef为0x06000000,mdtEvent为0x14000000等等,而余下的24bit则为此类TOKEN的唯一识别。EnrtyPointToken只能是一METHOD,而不能是EVENT等等。如App.Exe的EnrtyPointTokeno为0x06000001,其对应于Main Method。您可以使用ildasm.exe(随.NET Framework SDK提供)进行验证。 
       App.exe的CLR Header如下(只列出了部分非空字段): 
       Size: 0x00000048 
       MajorRuntimeVersion: 0x0002 
       MinorRuntimeVersion: 0x0000 
       MetaData 
       VirtualAddress: 0x0000207C 
       Size: 0x00000200 
       Flags: 0x00000001 
       COMIMAGE_FLAGS_ILONLY 
       EntryPointToken: 0x06000001 
       .NET MetaData由MetaData成员指定。Microsoft在CorHdr.h中给出了ILMETHOD的on disk组织结构(IMAGE_COR_ILMETHOD)。随.NET Framework SDK也提供了一个例子metainfo用于分析Metadata。随QuickStart例子的Class Browser的ASP.NET范例也是.NET Framework很好的学习材料。Metainfo使用常规的COM方法,而Class Browser使用.NET Framework的System.Reflection Namespace。关于.NET的SOAP,Web Services,Web Forms,XML等等QuickStart真不愧为QuickStart,.NET看来是下阵子学习的方向啊。
       最后应该说明的是对于.NET我真有一种很自清新的感觉,自身也是刚刚接触,本文仅是抱着学习的态度,权当自己的学习笔记,与各位进行交流。文中有误之处或是有所建
  • 相关阅读:
    背景图片自适应大小(平铺)
    墨卡托投影示意图
    C# 两个类的实例之间相同属性的值的复制
    C# 并行编程 Task
    C# 并行编程 PLINQ
    C# 并行编程 Parallel
    仰望星空
    Ubuntu的人道精神
    神经网络简介
    并行计算简介
  • 原文地址:https://www.cnblogs.com/hgy413/p/3693437.html
Copyright © 2020-2023  润新知