托管PE文件

文/玄魂

 

 中间语言

在.NET框架中,公共语言基础结构使用CLS来绑定不同的语言。通过要求不同的语言至少要实现CTS包含在CLS中的部分,公共语言基础结构允许不同的语言使用.NET框架。因此,在.NET框架中,所有的语言(C#、VB.NET、Effil.NET等)最后都被转换为了一种通用语言:微软中间语言(Microsoft Intermediate Language,MSIL,以下简称IL)。

IL是一种介于高级语言和基于Intel的汇编语言的中间语言,是.NET平台的汇编语言。当用户编译一个.NET程序时,编译器将源代码翻译成一组可以有效地转换为本机代码且独立于CPU的指令。当执行这些指令时,实时编译器将它们转化为CPU特定的代码。由于CLR支持多种实时编译器,因此同一段IL代码可以被不同的编译器实时编译并运行在不同的结构上。

IL包括用于加载、存储和初始化对象以及对对象调用方法的指令,还包括用于算术和逻辑运算、控制流、直接内存访问、异常处理和其他操作的指令。要使代码可运行,必须先将 IL 转换为特定于 CPU 的代码,这通常是通过实时(JIT) 编译器来完成的。由于CLR为它支持的每种计算机结构都提供了一种或多种JIT编译器,因此同一组IL可以在所支持的任何结构上JIT编译和运行。

当编译器产生IL时,它也产生元数据。元数据描述代码中的类型,包括每种类型的定义、每种类型的成员的签名、代码引用的成员和运行库在执行时使用的其他数据。IL和元数据包含在一个可移植可执行(PE)文件中,下面重点介绍托管PE文件,以及元数据的相关知识。

1.3.1       托管PE文件

PE(Portable Execute,可移植执行体)是微软Windows操作系统上的程序文件,常见的如EXE、DLL、OCX、SYS、COM。图1-3展示了标准的PE/COFF文件头部格式。

 

图1-3 标准的PE/COFF文件头部格式

MS DOS头是DOS系统的遗传内容,表示一个应用程序可以在DOS环境下运行。MS DOS根(stub)是一段代码,如果Windows程序在DOS环境下运行,会给出“该程序不能在DOS环境下运行”(This program cannot be run in DOS mode)的提示。在偏移量0x3c处,MS DOS头指向了PE标识(PE Signature)的地址。

PE标识表示该文件是一个PE文件。其值始终为00004550h,45h代表字符E,50h代表字符P。

COFF头(COFF Header)提供了COFF或者可执行文件的最一般的信息。

PE头(PE Header)提供了操作系统加载文件所需的信息。这对于PE文件是最重要的地方,其间包含了数据索引表和节。

关于标准PE文件的详细内容请读者阅读相关资料,本节内容只关注托管PE文件的特殊信息。CLR对传统的PE文件进行了扩展,如图1-4所示是托管PE文件的格式。

 

图1-4 托管PE文件的格式

标准的Windows PE文件头和COFF(通用对象文件格式)头类似,分为PE32和PE32+两种。如果文件头采用PE32格式,则该文件可运行在32位或64位操作系统上。如果文件头采用PE32+格式,则该文件只能在64位的操作系统上运行。PE32 或者 PE32+ 头也包含文件类型信息:GUI、CUI或者DLL。如果包含本地CPU代码的模块,则PE32或者PE32+ 头将包含有关本地CPU代码的相关信息。

CLR头包含使这个模块被托管的相关信息。这些信息包括CLR需要的版本信息、一些标识、入口方法的元数据信息、模块的元数据位置和大小信息、资源信息、强名称和一些其他信息。

每一个托管模块都包含元数据表。元数据表有两种,一种是描述源代码中的类型描述和成员描述的元数据表,另一种是包含源代码引用的类型描述和成员描述的元数据表。

IL代码是编译器编译产生的中间代码,程序运行时CLR负责将中间代码编译成本地代码执行。

CLR头定义在.NET Framework的CorHdr.h中,代码如代码清单1-4所示。

代码清单1-4 CLR 头定义

 1 typedef struct IMAGE_COR20_HEADER
 2 
 3 {
 4 
 5 ULONG cb;
 6 
 7 USHORT MajorRuntimeVersion;
 8 
 9 USHORT MinorRuntimeVersion;
10 
11 // Symbol table and startup information
12 
13 IMAGE_DATA_DIRECTORY MetaData;
14 
15 ULONG Flags;
16 
17 union {
18 
19 DWORD EntryPointToken;
20 
21 DWORD EntryPointRVA;
22 
23 };
24 
25 // Binding information
26 
27 IMAGE_DATA_DIRECTORY Resources;
28 
29 IMAGE_DATA_DIRECTORY StrongNameSignature;
30 
31 // Regular fixup and binding information
32 
33 IMAGE_DATA_DIRECTORY CodeManagerTable;
34 
35 IMAGE_DATA_DIRECTORY VTableFixups;
36 
37 IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
38 
39 IMAGE_DATA_DIRECTORY ManagedNativeHeader;
40 
41 } IMAGE_COR20_HEADER;

 

关于CLR头中的各个字段的解释见表1-1,后文会对PE文件中的节信息做简要介绍,关于PE文件的详细信息参看书后附录中的参考书籍。

表1-1  CLR头字段说明

偏移(offset

大小(size

字段(field

描述(description

0

4

Cb

头的长度(bytes)

4

2

MajorRuntimeVersion

CLR运行程序所必须的最小版本(Minimum Version)信息的主码(Major Number)

6

2

MinorRuntimeVersion

CLR运行程序所需要的版本信息中的次要编码(Minor Number)

8

8

MetaData

相对虚拟地址(RAV)和元数据的大小

16

4

Flags

二进制标志位组合,包含系统相关,程序调用等相关信息

20

4

EntryPointToken/EntryPointRVA

文件的入口点元数据标识符,对于DLL文件可以被设置为0

24

8

Resources

托管资源的大小和相对虚拟地址

32

8

StrongNameSignature

当前PE问件的hash数据的大小和相对偏移地址,被加载器用来绑定和版本验证

40

8

CodeManagerTable

Code Manager table的大小和相对偏移地址。目前为保留字段被设置为0

48

8

VTableFixups

一组V-Table的大小和相对虚拟地址信息

56

8

ExportAddressTableJumps

用于C++的输出跳转地址表的RVA和size,大多数情况为0

64

8

ManagedNativeHeader

为本地映像的保留字段,设置为0

    

下面通过ILDasm查看HelloWorld.exe的文件头信息。单击菜单“view-headers”,如图1-5所示。

 

图1-5 查看文件头信息

头信息的主要代码如代码清单1-5所示。

代码清单1-5 HelloWorld.exe 头信息

----- DOS Header:Magic:                      0x5a4dBytes on last page:         0x0090......(省略)File addr. of COFF header:  0x0080----- COFF/PE Headers:Signature:                  0x00004550----- COFF Header:Machine:                    0x014cNumber of sections:         0x0003Time-date stamp:            0x4b1b1d3aPtr to symbol table:        0x00000000Number of symbols:          0x00000000Size of optional header:    0x00e0Characteristics:            0x0102----- PE Optional Header (32 bit):Magic:                          0x010b......(省略)Directory:      ......(省略)Table:     0x00000000 [0x00000000] address [size] of Delay Load IAT:           0x00002008 [0x00000048] address [size] of CLR Header:               ......(节信息,略)Base Relocation Table0x00002000 Page RVA0x0000000c Block Size0x00000002 Number of EntriesEntry 1: Type 0x3 Offset 0x000007a0Entry 2: Type 0x0 Offset 0x00000000Import Address TableDLL : mscoree.dll......(省略)Delay Load Import Address Table// No data.Entry point code:FF 25 00 20 40 00----- CLR Header:Header size:                        0x00000048Major runtime version:              0x0002Minor runtime version:              0x0005......(省略)        Metadata HeaderStorage Signature:......(省略)Storage Header:0x00 Flags0x0005 Number of StreamsStream 1:0x0000006c Offset0x000001e8 Size'#~' Name......(省略)Stream 5:0x00000510 Offset0x00000130 Size'#Blob' NameMetadata Stream Header:0x00000000 Reserved0x02 Major0x00 Minor0x00 Heaps0x01 Rid0x0000000900001547 MaskValid0x000016003325fa00 SortedCode Manager Table:defaultExport Address Table Jumps:// No data.

 

上面代码中涉及很多节信息,下面做简要论述。

1.       Relocation(重定位)

映像文件的.reloc节包括了Fixup表,它包含了映像文件中的所有定位项。.reloc节的RVA和大小都由PE头的基地址重定位(Base Relocation)表目录定义。Fixup表由定位块组成,每个块都包括了一个4KB页的定位。这些块都是4字节对齐的。

每个定位都描述了映像文件中特定地址的位置,以及操作系统加载程序在将映像文件载入内存的时候,应该如何修改这个位置上的地址。

每个定位块都开始于两个4字节无符号整数:页面的RVA,这个页面包含了需要定位的地址、块的大小。紧随其后的是页面的定位项每个项都是16位宽的,其中的4个最高权重位包括了所需要的重定位类型,剩下的12位包括了页面中重定位地址的偏移量。

为了对地址进行重定位,操作系统加载程序会计算出首选的基地址(PE头的ImageBase字段)和实际加载映像文件的基地址之间的差异(delta)。接着根据重定位的类型,将这个delta应用到地址上。如果在首选位置加载映像文件,就不需要进行定位。

说明 Windows XP或者更新的版本都是支持CLR的操作系统,既不需要CLR的启动Stub,也不需要IAT来调用CLR。因此,如果CLR头标志指出映像文件是纯IL(COMIMAGE_FLAGS_ ILONLY),那么操作系统就会完全地忽略.reloc节。

2.       Text(文本)

PE文件的.text节是只读节。在托管PE文件中,它包括了元数据表、IL代码、导入表、CLR头、CLR非托管启动Stub。在由IL汇编器生成的映像文件中,这个节还包括了托管资源、强签名的散列值、调试数据以及非托管导出Stub。所以.text节是托管PE文件对传统PE文件改变最多的地方。

图1-6总结了由IL汇编器生成的映像文件的.text节的通用结构。

 

图1-6 .text节的通用结构

3.       Data(数据)

由IL汇编器生成的映像文件的数据节(.sdata)是可读写的节,它包括了数据常量、V表、非托管导出表以及TLS的目录结构。声明为特定于线程的数据位于一个不同的节,也就是.tls节。

4.       Data Constants(数据常量)

数据常量代表了静态字段的映射,通常包括映射字段的初始化数据。

字段映射是一种使用ANSI字符串、Blob或结构来初始化静态字段的方法。另一种初始化静态字段的方法(对于CLR来说更正式的方法)是通过在类的构造函数中显式地进行初始化。

一方面,映射到数据节的字段就像类型控制和垃圾收集那样,是CLR控制机制所触及不到的;另一方面,它是完全开放的,可以不受限制地访问和修改。这将导致加载程序阻止特定的字段类型被映射。映射字段的类型不能包括对象引用、向量、数组或任何非公共的子结构。如果为静态字段初始化使用类的构造函数,就不会出现这样的问题。

5.       V-Table(V表)

在纯粹的托管代码模块中,V表用于将托管方法公开给非托管代码来调用。V表由一些项组成,每个项又由一个或多个槽组成。V表的这些项和槽都定义在V表定位中。每个定位指定了每个项中槽的数量和宽度(4字节或8字节)。V表的每个槽都包含各个方法的元数据标记,这些元数据标记在运行期间将会替换成方法本身的地址或者封送thunk,用于提供方法的非托管入口。因为这些定位是在运行期间执行的,所以托管PE文件的V表必须驻留于可读写的节中。IL汇编器将这个V表放在了.sdata节中,不像VTFixup表是驻留于.text节中的。

非托管映像文件的V表完全在链接期间定义,并只需操作系统加载程序执行的基地址重定位。因为在执行期间不需要改变V表(例如把方法标记替换成托管映像中的地址),所以非托管映像文件可以把它们的V表放在只读节中。

6.       Unmanaged Export Table(非托管导出表)

在非托管映像文件中的非托管导出表占据一个单独的节——.edata。在IL汇编器生成的映像文件中,非托管导出表和它引用的V表都驻留于.sdata节中。

7.       Thread Local Storage(线程局部存储)

ILAsm和VC++允许用户定义属于TLS的数据常量,并将静态字段映射到这些数据常量上。TLS是一种特殊的存储类,类中的数据对象不是栈变量而是各个独立线程的局部变量。因此,每个线程都可以为这样的变量维护不同的值。

TLS数据在TLS目录中描述,IL汇编器将其放置于.sdata节中。32位映像文件的TLS目录结构定义在Winnt.h中,如代码清单1-6所示。

代码清单1-6 32位映像文件的TLS目录结构

typedef struct _IMAGE_TLS_DIRECTORY32 {ULONG StartAddressOfRawData;ULONG EndAddressOfRawData;ULONG AddressOfIndex;ULONG AddressOfCallBacks;ULONG SizeOfZeroFill;ULONG Characteristics;} IMAGE_TLS_DIRECTORY32;

 

64位映像(IMAGE_TLS_DIRECTORY64)的TLS目录结构是类似的,除了开头的4个字段是8字节无符号整数(ULONGLONG),而不是4字节无符号整数(ULONG)。

TLS目录结构的RVA和大小存储在PE头的第10个数据目录(TLS)中。构成了TLS模板的TLS数据常量,驻留于映像文件的.tls节中。

8.       Resources(资源)

在托管PE文件中可以嵌入两种不同的资源:特定于平台的非托管资源和特定于CLR的托管资源。它们驻留于托管映像文件的不同节,并通过不同的API进行访问。

(1)       Unmanaged Resources(非托管资源)

非托管资源在PE文件的.rsrc节中。嵌入的非托管资源的起始RVA和大小都在PE头的资源数据目录中表示。

非托管资源由类型、名称和语言进行索引,并根据这三个特征的顺序进行二进制排序。

IL汇编器创建.rsrc节,并且会嵌入命令行选项指定的.res文件中的非托管资源。编译器只能为每个模块嵌入一个非托管资源文件。

当IL反汇编器分析托管PE文件并找到.rsrc节的时候,它会从这个节中读取数据和结构,并流并释放出包括在PE文件中所有非托管资源的.res文件。

(2)       Managed Resources(托管资源)

CLR头的Resource字段包括了内嵌在PE文件中的托管资源的RVA和大小。它与PE头的Resource目录无关,后者指定了特定于平台的非托管资源的RVA和大小。

在IL汇编器生成的PE文件中,非托管资源驻留于映像文件的.rsrc节中,而托管资源和元数据、IL代码等都位于.text节中。托管资源在.text节中连续地存放。元数据携带着ManifestResource记录,每一笔记录对应着一个托管资源,包括了托管资源的名称以及从CLR头的Resources字段中指定的起始RVA算起的资源开始处的偏移量。在这个偏移位置上,会使用4字节无符号整数指出资源的字节长度。紧跟其后的是资源本身。

当IL反汇编器处理托管映像文件并找到嵌入的托管资源时,它会将每个资源各自写到根据资源名称命名的单独文件中。

当IL汇编器创建PE文件时,它会根据资源名称读取在源代码中定义为嵌入资源的所有托管资源,将它们写到.text节中,并在每个资源的前面放置该资源的指定长度。

-----------------------注:本文改编自《.net 安全揭秘》1.3节

 

 

转载于:https://www.cnblogs.com/xuanhun/archive/2012/05/23/2515392.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/297047.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

带你见识不一样的世界,这5部豆瓣纪录片不可错过!

全世界只有3.14 % 的人关注了爆炸吧知识纪录片一直都是增长见识又带给你力量的东西,你可能忙于学业、生活、工作而不能行万里路,但至少你还可以看纪录片,从一方屏幕看到整个世界。今天就为大家整理了5部高分纪录片,文末附领取方式…

客户要求ASP.NET Core API返回特定格式,怎么办?(续)

前言上次,我们用客户就要求API的返回值属性名必须是PascalCase(如UserName),但是这些API需要同时提供给内部系统使用,默认都是CamelCase(如userName)。其实,返回的都是JSON格式&…

打造自己博客(wordpress)的wap手机版本

这儿介绍我试用的两款插件:wordpress-mobile-edition和wp-t-wap。1.先说一下两者的区别。 wordpress-mobile-edition插件使用后,可以用手机直接访问你的博客主域名,手机会自动调整成wap版本。我的诺基亚6730上测试,自带的浏览器可…

猴子偷桃php代码,C++实现猴子吃桃的示例代码

题目详情有一天,某只猴子摘了一些桃子,当时吃了一半,又不过瘾,于是就多吃了一个。以后每天如此,到第n天想吃时,发现就只剩下一个桃子。输入n,表示到第n天剩下1个桃子,请计算第一天猴…

网吧也用VDI?

升级360以后,挨个菜单都点了一遍,虽然没啥用处,清清垃圾,升级下软件,清理下启动项还是很不错滴。 清理启动项的时候就搞笑了,发现Citrix联机插件居然被360识别为网吧无盘工作站连接中心。ICA Client我想了好…

socket python json_python实现的基于TCP的JSON数据通信

用Python写的一个多线程TCP通信实例,实现了JSON数据的传输。闲言少述,直接上代码​一、client#!/usr/bin/env python# -*- coding:utf-8 -*-#import socketimport threadingimport SocketServerimport jsondef client(ip, port, message):sock socket.s…

知乎超高赞:见识多的人,平时都在看些什么?

全世界只有3.14 % 的人关注了爆炸吧知识微信新功能总在悄咪咪更新,“拍一拍”一出,很多小伙伴都会收到各种群里面千奇百怪的“拍一拍”,到底都是谁在偷偷关注你?真正决定人与人之间的差距的,其实是我们对事物的见识与内…

django 1.3下关于静态文件staticfiles的设置

Django 1.3版本发布有些日子了,在站点被屏蔽的这段时间里学习也处于荒废状态,因此到今天才真正接触到新版下Static文件的处理设置,希望不算太晚。更改设置涉及的文件:settings.py1import os.path2HERE_PATHos.path.dirname(__file…

究竟是什么可以比反射还快实现动态调用?| Source Generators版

前言最近在公众号上看到一篇文章《究竟是什么可以比反射还快实现动态调用?》,它使用的是Newbe.ObjectVisitor,基于C#表达式树访问一个普通class的所有属性和对应的值,可以拥有比直接使用反射快上10倍的性能。就这一需求来说&#…

ofbiz中的数据模型

DelegatorDelegator是整个ofbiz中数据库访问的入口,具体实现是GenericDelegator类,在这个类中通过protected ModelReader modelReader null;protected ModelGroupReader modelGroupReader null;这两个属性变量去查找在xml文件中定义的数据模型ModelRea…

oracle 大页配置,【Oracle】Oracle如何开启大页

前言:在Linux中配置hugepage可以提高oracle的性能,减少oracle sga的页交换,类似于aix中的lagepage。为什么 使用大页?LINUX内存的默认块大小是4K如果SGA为:128Gselect 128* 1024* 1024/4 from dual;33554432个块(三千多…

python关联分析sklearn_Python3利用pandas,sklearn进行关联度分析以及预测的demo

做个简单的demo记录下,防止忘记先看原始数据:一共有5列:日期,金钱,性别,工作年限,年龄。我们的目的是要分析各个维度对金钱的影响。关联度分析代码:# -*- coding: utf-8 -*-from numpy import a…

NLB+Cluster(一)

这也算是个群集系列版吧!首先在前面大家已经看到了利用openfiler建立仲裁磁盘,然后通过Linux开源软件openfiler与windows群集的结合一文看到了windows cluster群集上如何构建文件共享及DHCP服务。那么本次我们将要升级到一个较高的层次,来看一…

只要懂得拒绝,哪会有什么狗血感情与莫名其妙的误会

1 就凭你?也想握朕的手?2 来,快站好~抱好娃!拍全家福啦!3 自我约束有利于家庭和谐,嗯!4 问题来了,你是夜灯党还是漆黑党?你点的每个赞,我都认真当成了喜欢

JS设置文本框只能是数字和小数点。

核心提示&#xff1a;JS判断只能是数字和小数点 只能输入字母和汉字 只能输入字母和汉字 JS判断只能是数字和小数点 1.文本框只能输入数字代码(小数点也不能输入) <input οnkeyup"this.valuethis.value.replace(/\D/g,)" onafterpaste"this.valuethis.value…

如何使用 Linq 获取每个分组中的第一个元素?

咨询区 Arian&#xff1a;考虑下面的记录:Id F1 F2 F3 -------------------------------------------------1 Nima 1990 102 Nima 1990 113 Nima 2000 …

oracle unpivot 空值,sql – 处理UNPIVOT中的NULL值

这很难看,但不依赖于必须找到NULL的带外替换&#xff1a;declare pivot_task table(age int null,[a] numeric(8,2),[b] numeric(8,2),[c] numeric(8,2),[d] numeric(8,2),[e] numeric(8,2));insert into pivot_task values (18, 0.5, null, 0.6, 1.21, 1.52),(19, 7.51, 6.51,…

android笔记之在WebView中显示ProgressBar的两种方法

http://blog.csdn.net/liuzhidong123/article/details/6450334 本文基于Creative Commons Attribution 2.5 China Mainland License发布&#xff0c;欢迎转载&#xff0c;演绎或用于商业目的&#xff0c;但是必须保留本文的署名http://www.cnblogs.com/luminji&#xff08;包含…

绝对不能错过!2009~2019 高中数学联赛11年真题解析

全世界只有3.14 % 的人关注了爆炸吧知识参加过高中数学联赛的同学都知道&#xff0c;全国高中数学联赛作为中国数学会及各省、市、自治区数学会的一项经常性工作&#xff0c;是属于较高等级的数学竞赛&#xff0c;其地位远高于各省自行组织的数学竞赛。为什么这个竞赛会这么特别…

在Win7中怎样打开摄像头?

在Win7中怎样打开摄像头&#xff1f;标题所说的问题在我装了win7后也遇到了&#xff0c;当时我也只会用等下我说的第一个方法打开摄像头&#xff0c;不过幸运的是我在前些天了解到了另外一个方法&#xff0c;那么现在我先讲下这个问题出现的原因吧&#xff1a;在Win7推出后就因…