现在的位置: 首页 > 综合 > 正文

NET程序集01

2018年02月07日 ⁄ 综合 ⁄ 共 6602字 ⁄ 字号 评论关闭

【文章标题】: NET程序集01
【文章作者】: 有酒醉
【作者邮箱】: wuqr32@sina.com
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
一、程序集的物理结构
程序集是代码部署的基本单位,它们为代码形成了合乎逻辑的安全以及版本边界.程序集包含了许多文件:
a、包含了主模块的可移植可执行(PE)文件
b、包含了其他模块的任意数量的可选PE文件
c、包含数据的任意数量的可选资源文件,这种文件可以是任何格式的文件

在Windows操作系统上,统一的格式为PE格式.一个PE格式不仅仅包含代码,还包含与应用程序相关联的初始化之前的数据结构。
PE文件结构的总体层次分布如下:

    +-------------------+
    | DOS-stub          |
    +-------------------+
    | file-header       |
    +-------------------+
    | optional header   |
    |- - - - - - - - - -|
    |                   |
    | data directories  |
    |                   |
    +-------------------+
    |                   |
    | section headers   |
    |                   |
    +-------------------+
    |                   |
    | section 1         |
    |                   |
    +-------------------+
    |                   |
    | section 2         |
    |                   |
    +-------------------+
    |                   |
    | ...               |
    |                   |
    +-------------------+
    |                   |
    | section n         |
    |                   |
    +-------------------+

每一层次的各个部分都有特定的结构,可以在WinNT.h中查找PE头文件的信息.下面简单讲解一下Windows加载PE文件的主要步骤:
a、当PE文件被执行,PE装载器检查DOS MZ header 里的PE header 偏移量.如果找到,则跳转到PE Header
b、PE装载器检查PE header 的有效性.如果有效,就跳转到PE header的尾部.
c、紧跟 PE header 的是节表.PE装载器读取其中的节信息,并采用文件映射方法将这些节映射到内存,同时附上节表里指定的节属性
d、PE文件映射入内存后,PE装载器将处理PE文件中类似 Import Table 逻辑部分.

CLR的PE扩展,以下引用自看雪论坛:

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组成的供.NET Framework运行的支撑部分。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。随uickStart例子的Class Browser的ASP.NET范例也是.NET Framework很好的学习材料。Metainfo使用常规的COM方法,而Class Browser使用.NET Framework的System.Reflection Namespace。

<续>

--------------------------------------------------------------------------------
【版权声明】: 本文原创于泉州软件基地, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年03月27日 17:21:08

 

【上篇】
【下篇】

抱歉!评论已关闭.