Flier Lu <flier_lu@sina.com.cn> 
  注意:本系列文章在水木清华BBS(smth.org)之.Net版首发, 
     转载请保留以上信息,发表请与作者联系   
Metadata 篇   
第一章 Metadata 概述   
1.1 什么是 Metadata   
    Metadata翻译成中文是“元数据”,可以理解为Type of Type, 
说白了就是描述类型的类型数据。从最初级的语言层面支持的RTTI 
(“近代”的编程语言基本上都提供了足够的支持,如C++,Delphi等, 
部分较“落伍”的语言也通过不同形式如扩展库提供了模拟支持, 
“现代”的编程语言则提供了强力的支持,如Java和C#<本质是CLR>), 
到后来二进制级的COM的IDL和类型库(类型库是IDL编译后的二进制形式), 
到现在的Metadata,其实是遵循着相同的设计思路。只是出于不同的需求 
设计、实现,有这各自的优点缺点罢了。但随着语言的发展,更多的需求集中在 
灵活性方面,因而语言发展的趋势是元数据的使用越来越多、支持越来越强。 
    举个最简单的例子,在IDE中,动态显示当前对象的方法、属性名列表的功能 
(MS叫IntelliSense,Borland叫CodeInsight),就得宜于类型信息 
以前在VC里实现,比较麻烦,得生成专门的符号库;在VB里强一点,可以通过 
COM的IDispatch,ITypeInfo,ITypeLib等接口动态获取,但编程麻烦要死; 
到CLR,库一级直接提供支持,可以通过System.Reflection完全控制 
甚至比COM类型库更高一级地支持动态创建。 
   对用户来说,可以完全了解当前程序接口,有哪些Module,哪些Class, 
哪些Method等等,这给开发者提供了巨大的创造空间。如DUnit(DotNet下 
的XUnit单元测试平台)就大量使用Reflection机制,我们等会谈使用时再说。   
1.2 Metadata在CLR中的作用   
    对于CLR架构来说,Metadata可以算是核心操作对象,几乎绝大多数功能 
都需要参考其数据。从静态的IL代码构成(二进制编码中直接使用Metadata里的Token) 
到动态JIT编译器(使用Metadata定位IL代码及其关系);从简单的代码载入执行 
(Class Loader通过Metadata定位代码入口、编译执行)到复杂的不同语言互操作 
(如VB.Net继承C#的类,实际上是直接继承CLR中Metadata中的类);等等…… 
几乎所有地方都能看到Metadata的身影。   
    因为本文的主要目的是介绍底层结构,这里就不再罗嗦Metadata的好处了, 
反正以后文章中大家会次次看到他,各种优点自己慢慢体会吧 :)   
1.3 如何访问和使用 Metadata   
   做了一通广告,大家一定很关心如何使用Metadata,听我慢慢道来 
   在CLR里使用Metadata,可以在三个层面进行操作。 
   最简单的方法是直接通过类库提供的System.Reflection命名空间中的 
若干类进行访问,例如   
using System.Reflection; 
using System;   
 public class Simple 
 { 
    public static void Main () 
    { 
         Module mod = Assembly.GetExecutingAssembly().GetModules () [0]; 
         Console.WriteLine ("Module Name is " + mod.Name); 
         Console.WriteLine ("Module FullyQualifiedName is " + 
mod.FullyQualifiedName); 
         Console.WriteLine ("Module ScopeName is " + mod.ScopeName); 
    } 
 }   
   这种访问方式使用起来最简单,功能也足够强大,能够完成我们绝大多数的需要, 
特别是在System.Reflection.Emit命名空间中,更提供了动态生成、修改的支持 
功能强大得我都想不出能有什么改进了 :) (写.Net病毒就靠他了,hoho) 
   不过这种方式必须有CLR环境的支持,受到库功能的限制(后面我们会看到很多 
在Reflection一级里不提供的信息:),因此MS为工具软件开发商提供了另一套 
较底层的开发库,Metadata Unmanaged API。这套库通过一系列COM接口, 
提供了直接访问Metadata的强大支持,System.Reflection应该就是使用它实现的。 
有兴趣的朋友可以参看FrameworkSDK\Tool Developers Guide\docs 
目录下的Metadata Unmanaged API.doc文档,里面有详细的说明。 
如同其名字所示,它必须用Unmanaged代码来使用,如传统的VC,Delphi等。 
   可以说99%的工作,都可以通过上面两套库来完成,不过总有些象我这样的人, 
喜欢对技术追根究底,想把隐藏在美好面纱下的底层架构纠出来暴露一把,呵呵 
因此有了第三个层面,二进制层面的逆向工程分析。 
   好在MS为了让其CLI(CLR的子集)标准化,公开了大量文档,总算没要我用上 
SoftIce之类的牛刀,Partition II Metadata.doc文档中对Metadata的 
二进制格式实现给出了比较详尽的说明,加上GNOME的mono项目已经做了很多工作 
因而对Metadata的二进制层面分析不是那么困难。 
   接下去的文章中,我会逐渐将Metadata在PE中的组织结构逐渐剥离开来, 
让大家能够了解这个神秘的CLR核心到底是什么,里面隐藏了些什么,我们能够通过 
他做什么,为什么要这样设计,等等……   
1.4 Metadata在PE中的组织结构   
   说了一通废话后,回到正体上来,谈谈Metadata在PE中的组织结构。   
注意:这一章里面我只把Metadata结构的大概情况介绍一下,下一章会专门 
针对二进制模式分析进行详细讲解。如果你只想了解底层结构,可以跳过 
下一章。以后的文章也会遵循这种方式组织,讲一些结构、原理,跟着讲 
一些实际数据分析方法。   
   上次我们提到CLR的头信息里面专门有一个字段指向Metadata数据块, 
实际上这个数据块只是Metadata的一个头结构,保存