MS.Net CLR 扩展PE结构分析(1)

flier_lu 2002-03-04 02:12:52
MS.Net CLR 扩展PE结构分析

Flier Lu <flier_lu@sina.com.cn>

注意:本系列文章在水木清华BBS(smth.org)之.Net版首发,
转载请保留以上信息,发表请与作者联系

概述

本系列文章,将从系统层角度,通过对MS.Net CLR架构对PE映像结构的扩展的分析,
解析MS.Net CLR架构的底层部分运行机制,帮助读者从更深层次理解CLR中某些重要概念
本文读者应具备基本的Win32编程经验,了解.Net中常见概念意义,并对Win32之PE映像
结构有一定了解,具体结构请参看Matt Pietrek于1994.3发表在MSJ的经典文章
《Peering Inside the PE: A Tour of the Win32 Portable Executable
File Format》,与之重复的部分我一概跳过。
本系列文章,将分为几个大部分,首先是最重要的MetaData,其次是IL代码结构,
然后……我还没想好,呵呵。此外会根据需要穿插一下CLR核心概念、思想、技术的介绍。
至于CLR几个核心部件之间的关系与交互等问题,我热切期待TBSoft的大作,
我这里就不去抢他的话题了,呵呵。

前言

对一个优秀Win32程序员来说,对PE结构的了解是对Win32架构了解的必经之路,
而从Chicago(Win95的开发代号,Win95正式发布以前的文档对Win95的称呼)以来,
PE结构就相对稳定,直到MS.Net的出现,才发生了一些不大不小的变化。
之所以说是不大不小,是因为CLR基本上没有对PE结构进行改变,只是利用现有PE
结构的优良可扩展性,将其所需的信息扩展到PE映像中。具体一点说,就是利用了PE结构
中的IMAGE_OPTIONAL_HEADER.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
来保存服务于CLR的IMAGE_COR20_HEADER结构。此外的PE结构一律不变。
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR此节,原本是设计用于COM,但不知为何
一直没有被使用,现在用于保存.Net信息的最高级信息结构。
我们的分析也将集中在此结构以及相关信息的分析上。
IMAGE_COR20_HEADER结构的定义,可以在FrameworkSDK\include\CorHdr.h
文件中找到,如下:

// 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;

而详细的说明,则可以在FrameworkSDK\Tool Developers Guide\docs
目录中找到。因为要将CLR变为标准,MS这次一反常态,公开大量有价值的文档,
避免我等浪费时间去逆向过程,呵呵
此结构虽然字段较多,但实际上其核心在于MetaData,其他信息都是围绕着
MetaData服务。之间的关系,等会再慢慢道来。
cb是结构大小,MajorRuntimeVersion.MinorRuntimeVersion是版本号
指执行此程序所需的最低CLR版本号,目前一般设置为1.1。而现在发布的.Net
Framework的CLR版本一般为2.0。
Flags是Runtime Image描述标志,描述此映像的执行属性。如设置位
COMIMAGE_FLAGS_32BITREQUIRED=0x02,则此映像只能在32位系统上执行
对以后的64位CLR无效(MS.Net很大的一个功能就是为以后平滑过渡到64位
平台做准备,想想以前16位平台到32位平台过渡时的混乱,以及现在比以前翻了
n倍的代码量就恐怖,MS真是未雨绸缪啊,呵呵)。如果设置
COMIMAGE_FLAGS_STRONGNAMESIGNED=0x04,则此映像有strong name
signature(这个东东不知道怎么翻译好)。这个strong name signature
在CLR架构里起到了非常重要的作用。为什么这么说呢?因为这个strong name
signature起到Assembly的身份证的作用,它关系到CLR中一大堆概念的实现,
以后我会专门用一章篇幅来介绍他,这里暂且放下。
EntryPointToken则是指向IL程序的入口,类似于以前的
IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint的作用,只是以前的
AddressOfEntryPoint是一个RVA直接指向程序入口代码所在地址,
(不要告诉我你不知道RVA是什么啊,呵呵,赶快去看Peering Inside the PE)
而现在EntryPointToken指向一个Token。注意,是Token,因为IL代码是
JIT编译的,存在于映像中的都是IL形式的P-code(pseudo code),在需要时
才由CLR动态读取,在内存中编译展开为本机代码(Native Code),进而执行。
因此这里的程序入口执行的只是一个MethodDef或File表的入口,一个Token而已。
这里的MethodDef是一个MetaData表,每行定义一个方法;而File表则是
每行有一个File定义的表,每行包含一个外部文件的信息。也就是说,在执行程序时
可以直接编译执行此映像中的一个方法的IL代码,也可能是重定向到另一个文件,
这就是Assembly作为一个逻辑代码单元,与传统DLL之类相比一个很大的不同。
Assembly的概念也非常重要,我不想这里一下说完,以后专门拿一章出来讲好了。
剩下几个字段都是IMAGE_DATA_DIRECTORY类型,这个类型是一个数据块
定义结构,在Winnt.h中有定义
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
呵呵,知道RVA的意思了吧 RVA = Relative Virtual Address
Resources定义CLI资源;StrongNameSignature定义刚刚提到的
strong name signature;此外CodeManagerTable,
ExportAddressTableJumps,MangedNativeHeader都没用到。
VTableFixups暂且略过,以后用上时再详细解释。
这样一来,就剩下一个MetaData字段没有介绍了,不过这个重中之重的东东,
这次只言片语是无法介绍了,因为下面会有专门的一整篇——MetaData篇,
用n章的篇幅来详细剖析,呵呵

btw:因为自己以前不是搞Win32底层开发的,实在不知这种文章怎么写,
希望读者多多提意见,有没有解释清楚或者错误的地方尽管提出来。

分析.Net的CLR PE映像其实并不是什么困难的事情,有现成的
代码(mono)现成的文档(Tool Developers Guide)可以看,
只是代码比较难看(不习惯unix代码风格),文档比较长
(一共20几M,poor)而已。我是实在耐不住好奇心才动手分析的,
希望能够把自己分析的一些收获和体会写出来,节省其他朋友的时间。

希望能够有充足的时间、精力和耐心完成这个系列文章……

...全文
96 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

17,740

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET Framework
社区管理员
  • .NET Framework社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧