CLR探索系列:托管PE/COFF文件格式侧窥
一直都想写篇文章来说说那些尘封在PE/Coff文件格式下的那些事,还有Metadata和EEClass是如何表现了一个静态的PE格式文件在内存中的映射结构。
在这篇文章里,我不去介绍windows下PE文件的具体格式,也不去介绍一个托管或者是非托管PE文件的加载运行方式,更加不去介绍一个PE文件里面的各个头部以及整体结构的各个部分的含义。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
而是侧重于介绍,基于托管环境下,DotNet对基本的PE/CoFF文件格式做了那些扩充,CLR头部介绍,以及元数据和IL代码详析解析。主要侧重从静态文件的角度,来剖析DotNet下最基本的模块的结构,以及这样的结构如何适应一个托管的环境。
拟把PE文件格式里里外外从上到下一点一点的完全解剖一遍,当然,不可能做到很全面,不然,如果想知道PE文件的各个方面的具体的细节,可以参阅文章底部推荐的那个白皮书文档,这份文档相当详尽介绍了PE文件格式的点点滴滴。
首先,还是从一段C#代码开始:
class Program
{
public const int conField=122*1119;
public readonly int roField;
private int _property;
public int Property
{
get {return _property; }
set{_property = value; }
}
static void <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Main(string[] args)
{
(new Program()).Method();
}
public void Method()
{
System.Console.ReadLine();
}
}
之所以定义这么多类型和字段,主要是为了在解说托管PE文件格式的时候,元数据表中相关的表都会出现相关记录。
编译之后,得到一个叫做TestConsoleApp.exe的托管PE文件。在继续下面的叙述之间,首先先概括的说一下Metadata。不说IL语言是因为,在我以前的博文中,已经有相关的介绍。
一个托管PE文件,粗略的讲,由4个部分组成。PE32(+)的头部,CLR头部,Metadata以及IL。
首先,我们来说说CLR的头部。这个东西,是托管的PE文件所特有的东西。
我们打开DotNet Framework里面的include文件夹里面一个叫做CorHdr.h的文件,找到一个叫做IMAGE_COR20_HEADER这个数据结构的定义。这个数据结构,定义的就是CLR的header里面内容。下面对其的定义:
// COM+ 2.0 header structure.
typedef struct IMAGE_COR20_HEADER
{
// Header versioning
DWORD cb;
//CLR的主版本号
WORD MajorRuntimeVersion;
//CLR的副版本号
WORD MinorRuntimeVersion;
// Symbol table and startup information
//标识元数据在这个PE文件里面起始位置。
IMAGE_DATA_DIRECTORY MetaData;
//标识这个runtime的Flags
DWORD Flags;
// DDBLD - Added next section to replace following lin
// DDBLD - Still verifying, since not in NT SDK
// DWORD EntryPointToken;
// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint.
//EnterPoint Token,这个定义的是这个image的MethodDef的入口点。
union {
DWORD EntryPointToken;
DWORD EntryPointRVA;
};
// DDBLD - End of Added Area
// Binding information
//标识CLI资源的目录
IMAGE_DATA_DIRECTORY Resources;
//强命名的签名文件。标识对这个PE文件计算得到的一个Hash文件的地址。这个是在CLI的loader在加载一个PE文件的时候,验证版本和加载的时候需要使用的。可以为空。
IMAGE_DATA_DIRECTORY StrongNameSignature;
// Regular fixup and binding information
//代码管理表的地址
IMAGE_DATA_DIRECTORY CodeManagerTable;
//这个module里面的一个包含地址的数组,数组的每一项,都包含了对一个founction的指针。
IMAGE_DATA_DIRECTORY VTableFixups;
//这个也是包含的一个数组,数组里面都是方法需要jump的地址。
IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
// Precompiled image info (internal use only - set to zero)
//这个地址,保存的是这个Module对应的在本机上面的Jit过后了的本地代码的目录。
IMAGE_DATA_DIRECTORY ManagedNativeHeadesr;
} IMAGE_COR20_HEADER, *PIMAGE_COR20_HEADER;
接下来,我们就直接打开上面编译好的那个托管模块的CLR头部,看看里面有些什么:
----- CLR Header:
Header size: 0x00000048
Major runtime version: 0x0002
Minor runtime version: 0x0005
0x00002094 [0x00000660] address [size] of Metadata Directory:
Flags: 0x00000001
Entry point token: 0x06000003
0x00000000 [0x00000000] address [size] of Resources Directory:
0x00000000 [0x00000000] address [size] of Strong Name Signature:
0x00000000 [0x00000000] address [size] of CodeManager Table:
0x00000000 [0x00000000] address [size] of VTableFixups Directory:
0x00000000 [0x00000000] address [size] of Export Address Table:
0x00000000 [0x00000000] address [size] of Precompile Header:
从上面的这个托管模块的头部可以看到,这个头部里面包含的内容,和这个头部的结构体所定义的东西,是完全一致的。
几个需要说明的,一个是Major runtime version,以及Minor runtime version标识的是不同的runtime的版本。在上面的头部中,主要是一个文件的偏移的offset,就是Entry point token的地址。
这里要特别提出来一点,这里的Entry point token表示的是入口点,是MethodDef的入口点。
而不是整个托管PE文件的入口点。整个PE文件的入口点,在这里,用PEID打开可以看到,是
Addr. of entry point: 0x000027be
这个EnterPoint是在一个32位的PE Optional Header里面定义的。这个入口点,才是整个应用程序的入口点。
这个入口点里面,我们使用IDA之类的逆向工程工具可以看到,托管PE模块在这个地址上面的代码:
004027BE: FF 25 00 20 40 00 jmp dword ptr ds:[402000] ; _CorExeMain
在这里,我们看到了熟悉的CorExeMain这个入口函数 ^_^ 关于这个函数,我就不多说了,在前面的博文里面有详析的分析。参见那篇探索托管模块加载过程的文章。
接下来,我们介绍下元数据表,以及一些对这个PE文件的统计信息,首先查看这个托管PE文件的统计信息,使用的还是ildasm工具,我的最爱:
File size : 16384
PE header size : 4096 (496 used) (25.00%)
PE additional info : 1075 ( 6.56%)
Num.of PE sections : 3
CLR header size : 72 ( 0.44%)
CLR meta-data size : 1632 ( 9.96%)
CLR additional info : 0 ( 0.00%)
CLR method headers : 16 ( 0.10%)
Managed code : 49 ( 0.30%)
Data : 8192 (50.00%)
Unaccounted : 1252 ( 7.64%)
Num.of PE sections : 3
.text - 4096
.rsrc - 4096
.reloc - 4096
CLR meta-data size : 1632
Module - 1 (10 bytes)
TypeDef - 2 (28 bytes) 0 interfaces, 0 explicit layout
TypeRef - 18 (108 bytes)
MethodDef - 5 (70 bytes) 0 abstract, 0 native, 5 bodies
FieldDef - 3 (18 bytes) 0 constant
MemberRef - 17 (102 bytes)
ParamDef - 2 (12 bytes)
Constant - 1 (6 bytes)
CustomAttribute- 13 (78 bytes)
StandAloneSig - 1 (2 bytes)
PropertyMap - 1 (4 bytes)
Property - 1 (6 bytes)
MethodSemantic- 2 (12 bytes)
Assembly - 1 (22 bytes)
AssemblyRef - 1 (20 bytes)
Strings - 680 bytes
Blobs - 236 bytes
UserStrings - 8 bytes
Guids - 16 bytes
Uncategorized - 194 bytes
CLR method headers : 16
Num.of method bodies - 5
Num.of fat headers - 1
Num.of tiny headers - 4
Managed code : 49
Ave method size - 9
可以看到,在上面的统计信息中,显示了一个托管的PE模块的各个部分的组成。从各个部分的统计的大小里面,PE Header和CLR的Metadata占据了相当大的比例,而IL代码,仅仅占据了整个托管模块大小的0.3%。只有49个字节。
顺便提一下,如果Unaccounted显示的是负数,是不能相信的,那是以前的版本存在的一个bug。
就写到这里吧,如果觉得看了上面的东西还是不知所云或者觉得不完整,那我推荐一本MS的白皮技术文档:Visual Studio, Microsoft Portable Executable and Common Object File Format Specification
可以在msdn上面下载到,它完整的讲述了PE文件格式的各个部分的细节。
接下来的一篇博文,就说说元数据以及元数据表的内存结构,逻辑结构和在SSCLI中的设计和实现。
最后做个广告:
欢迎园子里面的朋友加入SSCLI团队,这里,我们致力于对.Net底层核心技术及其实现的研究。如果你想真正的了解.Net最核心的实现,我们热忱的欢迎你的加入:
圈子地址:http://sscli.cnblogs.com
加入地址:http://www.cnblogs.com/lbq1221119/archive/2008/03/10/1097627.html
圈子刚刚建立,希望园子里的朋友多多支持,:)
CLR探索系列:托管PE/COFF文件格式侧窥相关推荐
- CLR探索系列:Windbg+SOS动态调试分析托管代码
http://blog.csdn.net/garyye/article/details/4788070 在使用VS进行托管应用程序的调试的时候,有的时候总感觉有些力不从心.譬如查看一个托管堆或者计 ...
- PE文件和COFF文件格式分析--概述
刚工作的时候,我听说某某大牛在做病毒分析时,只是用notepad打开病毒文件,就能大致猜到病毒的工作原理.当时我是佩服的很啊,同时我也在心中埋下了一个种子:我也得有这天.随着后来的工作进行,一些任务的 ...
- PE文件和COFF文件格式分析——导出表的应用——一种摘掉Inline钩子(Unhook)的方法
在日常应用中,某些程序往往会被第三方程序下钩子(hook).如果被下钩子的进程是我们的进程,并且第三方钩子严重影响了我们的逻辑和流程,我们就需要把这些钩子摘掉(Unhook).本件讲述一种在32位系统 ...
- PE文件和COFF文件格式分析——导出表的应用——通过导出表隐性加载DLL
通过导出表隐性加载DLL?导出表?加载DLL?还隐性?是的.如果觉得不可思议,可以先看<PE文件和COFF文件格式分析--导出表>中关于"导出地址表"的详细介绍.(转载 ...
- PE文件和COFF文件格式分析——导出表的应用——一种插件模型
可能在很多人想想中,只有DLL才有导出表,而Exe不应该有导出表.而在<PE文件和COFF文件格式分析--导出表>中,我却避开了这个话题.我就是想在本文中讨论下载Exe中存在导出表的场景. ...
- PE文件和COFF文件格式分析——导出表
在之前的<PE可选文件头>相关博文中我们介绍了可选文件头中很多重要的属性,而其中一个非常重要的属性是(转载请指明来源于breaksoftware的CSDN博客) IMAGE_DATA_DI ...
- PE文件和COFF文件格式分析——RVA和RA相互计算
之前几节一直是理论性质的东西非常多.本文将会讲到利用之前的知识得出一个一个非常有用的一个应用.(转载请指明来源于breaksoftware的csdn博客) 首先我们说下磁盘上A.exe文件和正在内存中 ...
- PE文件和COFF文件格式分析——节信息
在<PE文件和COFF文件格式分析--签名.COFF文件头和可选文件头3>中,我们看到一些区块的信息都有偏移指向.而我们本文讨论的节信息是没有任何偏移指向的,所以它是紧跟在可选文件头后面的 ...
- C 设计语言编译生成的是中间语言IL,一、源代码-面向CLR的编译器-托管模块-(元数据IL代码)...
本文脉络图如下: 1.CLR(Common Language Runtime)公共语言运行时简介 (1).公共语言运行时是一种可由多种编程语言一起使用的"运行时". (2).CLR ...
最新文章
- php透明颜色的代码,PHP 透明水印生成代码参考
- CTFshow 信息收集 web12
- CentOS下启动oracle数据库(转)
- 关于用户画像产品构建和应用的几点经验
- 计算机配置里面没有网络选项,主编教您win10网络设置中没有wlan选项怎么办
- python requests_小白学 Python 爬虫(18):Requests 进阶操作
- ITK:Sobel边缘检测图像滤镜
- jstack调试_增压的jstack:如何以100mph的速度调试服务器
- 简单聊一下makefile中的 =, :=, ?=和+=
- strlen函数_四种好用的PHP自定义加密函数(可逆/不可逆)
- 大话集群和负载均衡,太强了!
- Linux 命令(119)—— diff 命令
- 【全家福】多项式的各种板子
- 玩转二叉链表 (20 分)
- SWAT模型在水文水资源、面源污染模拟中的实践技术
- OpenCV的二值化处理函数threshold()详解
- 解决scrapy下载小说乱序
- 数字化转型之道:谈谈企业如何落地数据治理
- 1_requests请求
- 如何实现1分钟写一个API接口