0x0、序

  解析过程并没有介绍对pe结构的相关解析过程,网上此类相关资料很多可自行查阅,本文只介绍了网上资料较少的从pe结构的可选头中的数据目录表中获取dotnet目录的rva和size,到完全解析dotnet文件格式特有数据结构的部分。

  了解dotnet文件格式你可能需要一款名为CFF Explorer的工具;你也可能在很多时候需要查阅书籍《Expert .NET 2.0 IL Assembler》,该书籍的中文版本名为《.NET探秘MSIL权威指南》。简要的文件格式图,可以参考下面:

  分析文件的md5为:79D7AF997C9224CFF7B82E539C71FCDB。

0x1IMAGE_COR20_HEADER结构

  通过可执行文件nt头下的可选头中数据目录中最后一项获取dotnet目录的rva和size。获取的数据为:rva=0x00002008;size=0x00000048,使用stud_pe将rva地址转化为raw。得到raw地址为:0x208。读取出其中数据,数据内容如下:

00000200                            48 00 00 00 02 00 05 00           H

00000210   A0 23 00 00 58 10 00 00  03 00 02 00 06 00 00 06   ?  X

00000220   30 22 00 00 70 01 00 00  00 00 00 00 00 00 00 00   0"  p

00000230   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

00000240   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

  该长度为0x48的数据的数据结构如下:

typedef struct IMAGE_COR20_HEADER

{

ULONG         cb;

USHORT        MajorRuntimeVersion;

USHORT        MinorRuntimeVersion;

//符号表和开始信息

IMAGE_DATA_DIRECTORY    MetaData;

//信息都在这个元数据表中可以获取。

ULONG         Flags;

union{

DWORD    EntryPointToken;

DWORD    EntryPointRVA;

};

//绑定信息

IMAGE_DATA_DIRECTORY    Resource;

IMAGE_DATA_DIRECTORY    StrongNameSignature;

//常规的定位和绑定信息

IMAGE_DATA_DIRECTORY    CodeMagagerTable;

IMAGE_DATA_DIRECTORY    VTableFixups;

IMAGE_DATA_DIRECTORY    ExprotAddressTableJumps;

IMAGE_DATA_DIRECTORY    MagageNativeHeader;

}IMAGE_COR20_HEADER

  通过对结构解析,读取结构中的元数据MetaData。该结构中可以得到一个元数据的rva和size。具体数据内容为:MetaData_rva=000023a0,MetaData_size= 00001058。MetaData_rva转换成MetaData_raw后为5a0。需要注意的是后面好多数据的定位都是以这个地址为基准的相对偏移。

0x2、元数据

  MetaData_rva指向的数据结构如下:

typedef struct STORAGE_SIGNATURE

{

DWORD    lSignature;

WORD     iMajorVersion;

WORD     iMinorVersion;

DWORD    iExtraData;

DWORD    iLength;

BYTE     iVersionString[];

//字符串编译环境版本号的长度由iLength决定,包含尾部0,且按4字节对齐。

}STORAGE_SIGNATURE;

  结构的数据内容为:

000005A0   42 53 4A 42 01 00 01 00  00 00 00 00 0C 00 00 00   BSJB

000005B0   76 34 2E 30 2E 33 30 33  31 39 00 00               v4.0.30319

  紧跟存储标志结构后面的数据结构定义如下:

typedef struct STORAGE_HEADER

{

BYTE      fFlags;

BYTE      reserved;

WORD      NumberOfStreams;

}STORAGE_HEADER;

  结构的数据内容为:

000005B0                                        00 00 05 00

0x3、流描述表

  存储头结构的最后一个成员是流的个数,在该结构后面将跟的是每一个流的描述结构,该成员有几个流个数,后面就有几个流描述结构,分析的文件流个数为5,后面将跟5个流描述结构。每个结构的定义如下:

typedef struct STREAM_HEADER

{

DWORD    iOffset;

//相对于MetaData_raw的偏移

DWORD    iSize;

BYTE     rcName[];

//流名称字符串得长度由iSize决定,包含尾部0,且按4字节对齐。

}STREAM_HEADER;

  结构数据(不同的数据流之间已经用不同的颜色区分)为:

000005C0   6C 00 00 00 44 05 00 00  23 7E 00 00 B0 05 00 00   l   D   #~  ?

000005D0   8C 07 00 00 23 53 74 72  69 6E 67 73 00 00 00 00   ?  #Strings

000005E0   3C 0D 00 00 88 00 00 00  23 55 53 00 C4 0D 00 00   <   ?  #US ?

000005F0   10 00 00 00 23 47 55 49  44 00 00 00 D4 0D 00 00       #GUID   ?

00000600   84 02 00 00 23 42 6C 6F  62 00 00 00               ?  #Blob

  流名称字符串中的名称是由微软定义好的字符串,不会出现非定义的字符串。已经定义的流名称有:

名称

含义

#~

存储压缩(优化)后的元数据信息,存在#~流后不会出现#-流。

#-

存储未压缩(优化)的元数据信息,存在#-流后不会出现#~流。

#Strings

存储元数据的各种字符串,比如类名称,方法名称,成员名称,参数名称等。字符串格式为UTF8格式。该流数据首部会存在一个空字符串;且此处定义的字符串最大长度不超过1024。

#Blob

存储程序中的非字符串信息,包括常量值,方法的签名,强名称等。每个数据的长度由数据的前1-3位决定:0表示1字节;10表示2字节;110表示4字节。

#GUID

存储所有GUID

#US

存储IL代码中使用的各种字符串,字符串格式为Unicode格式。

0x4、元数据信息流

  微软定义的六个数据流中,除去一个互斥的元数据信息流外,其他的流都是可能存在的。而其他的流信息都是通过元数据信息流中的结构对其进行引用的。并且紧跟流表结构的也是元数据信息流,该地址可以通过流表中的元数据信息流流表中的相对便移地址计算得到:该流数据内容的地址相对元数据起始地址偏移为0x6c。和metadata_raw相加得到的地址为:0x60c。该地址数据结构如下:

typedef struct METADATA_HEADER

{

DWORD    Reserved;

BYTE     Major;

BYTE     Minor;

BYTE     Heaps;

BYTE     Rid;

QWORD    MaskValid;

QWORD    Sorted;

}METADATA_HEADER;

  结构下的数据内容为:

00000600                                        00 00 00 00

00000610   02 00 00 01 57 15 A2 15  09 01 00 00 00 FA 25 33       W ?     ?3

00000620   00 16 00 00

  结构中有两个域需要说明,分别是Heaps域和MaskValid域。

  结构中MaskValid是一个位向量,每一个二进制位表示某一个特定的表存在。该域所占大小为64位。但对应的表个数为45个,所有只有低45位有意义,其他位没有含义。位和表的对应关系如下:

位数

表名

位数

表名

0

Module

23

Property

1

TypeRef

24

MethodSemantics

2

TypeDef

25

MethodImpl

3

FiledPtr

26

ModuleRef

4

Filed

27

TypeSpec

5

MethodPtr

28

ImplMap

6

MethodDef

29

FiledRVA

7

ParamPtr

30

ENCLog

8

Param

31

ENCMap

9

MethodImpl

32

AssemblyRef

10

MemberRef

33

AssemblyProcessor

11

Constant

34

AssemblyOS

12

CustomAttribute

35

Assembly

13

FieldMarshal

36

AssemblyRefProcessor

14

DeclSecurity

37

AssemblyRefOS

15

ClassLayout

38

File

16

FieldLayout

39

ExportedType

17

StandAloneSig

40

ManifestResource

18

EventMap

41

NestedClass

19

EventPtr

42

GenericParam

20

Event

43

MethodSpec

21

PropertyMap

44

GenericParamConstraint

22

PropertyPtr

  分析文件的MaskValid值转换成二进制数值如下:

MaskValid值(16进制)

MaskValid值(2进制)

0000010915A21557

10000100100010101101000100001010101010111

  分析MaskValid的二进制数值,可以发现共有17个二进制位被置1,所以该文件的元数据流中存在17个类型的表。根据位对应编号得到存在的各个类型的表的序号分别为:0、1、2、4、6、8、10、12、17、21、23、24、26、28、32、35、40。查找上面的序号名称关系表可以查到对应的表名称。再通过紧跟其后的4字节数组确定表中有多少个记录。记录的个数可以确定表的长度。4字节数组内容如下:

00000620               01 00 00 00  31 00 00 00 05 00 00 00           1

00000630   05 00 00 00 0D 00 00 00  04 00 00 00 36 00 00 00               6

00000640   16 00 00 00 01 00 00 00  02 00 00 00 03 00 00 00

00000650   04 00 00 00 01 00 00 00  01 00 00 00 01 00 00 00

00000660   04 00 00 00 02 00 00 00

  4字节数组后将是按照数组各个元素对应的记录表,各个记录表的顺序和4字节数组的中顺序相同,也是按照结构编号从小到大排列。但每个表里每个元素的结构可能并不相同。以第一个表Module表为例,如果文件存在该结构,由于该结构序号为0,所以必然为第一个结构。其记录结构如下:

typedef struct Module_Struct

{

WORD          Generation;

WORD/DWORD    Name;         //(在#String流中的偏移量)大小可能是word也可能是dword

WORD/DWORD    Mvid;         //(在#GUID流中的偏移量)大小可能是word也可能是dword

WORD/DWORD    EncId;        //(在#GUID流中的偏移量)大小可能是word也可能是dword

WORD/DWORD    EncBaseId;    //(在#GUID流中的偏移量)大小可能是word也可能是dword

}METADATA_HEADER;

  需要说明的是结构中后4个便宜量才用DWORD还是WORD由METADATA_HEADER结构中的Heaps域决定。

  结构中Heaps的含义为:元数据信息流中引用其他流中数据时,索引值的大小。

Heaps数值

含义

0

所有索引值均采用16位索引值

0x01

表示引用#String流时,索引值均为32位

0x02

表示引用#GUID流时,索引值均为32位

0x04

表示引用#Blob流时,索引值均为32位

  从上面的METADATA_HEADER结构中我们可以看到heaps的数值为0,索引均采用WORD类型大小,而通过4字节数组可以确定Module记录表的长度为1,所以具体的Module数据内容如下:

00000660                            00 00 0A 00 01 00 00 00

00000670   00 00

  其他记录数据同样通过该方式进行查询。

  其他表中元素结构相关信息可以查阅相关资料文档《.NET探秘MSIL权威指南》或《Expert .NET 2.0 IL Assembler》附录B。

文章pdf版本、分析文件、简要文件格式图 打包下载

Dotnet文件格式解析的更多相关文章

  1. ArcGIS三大文件格式解析

    原文:ArcGIS三大文件格式解析 Shape数据 Shapefile是ArcView GIS 3.x的原生数据格式,属于简单要素类,用点.线.多边形存储要素的形状,却不能存储拓扑关系,具有简单.快速 ...

  2. Android init.rc文件格式解析

    /***************************************************************************** * Android init.rc文件格式 ...

  3. mp4文件格式解析(转载)

    mp4文件格式解析 原作:http://blog.sina.com.cn/s/blog_48f93b530100jz4b.html 目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的 ...

  4. C++PE文件格式解析类(轻松制作自己的PE文件解析器)

    PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣 ...

  5. 解析prototxt文件的python库 prototxt-parser(使用parsy自定义文件格式解析)

    解析prototxt文件的python库 prototxt-parser https://github.com/yogin16/prototxt_parser https://test.pypi.or ...

  6. mp4文件格式解析(转)

    mp4文件格式解析 MP4文件格式带数据详解 MP4文件格式的解析,以及MP4文件的分割算法

  7. Qt的.pro文件格式解析

    Qt的.pro文件格式解析 在Qt中用qmake生成makefile文件,它是由.pro文件生成而来的,.pro文件的具体格式语法如下: 1.注释 .pro文件中注释采用#号,从"#&quo ...

  8. flv文件格式解析!!!

    flv头 FLV header 总体上看,FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag组成. Signature: FLV 文件的前3个字 ...

  9. (转)AVI文件格式解析+AVI文件解析工具

    AVI文件解析工具下载地址:http://download.csdn.net/detail/zjq634359531/7556659 AVI(Audio Video Interleaved的缩写)是一 ...

随机推荐

  1. Selenium-java-Log4j环境搭建和

    1 导入Log4j ,我这版本是1.2.17  自己选择版本  **别告诉我不会导入 2  Path  奶瓶 3 创建一个与src同目录文件 命名为 log4.properties 4 文件的内容是, ...

  2. [LeetCode] Palindrome Permutation 回文全排列

    Given a string, determine if a permutation of the string could form a palindrome. For example," ...

  3. python cookbook 学习系列(一) python中的装饰器

    简介 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓 ...

  4. mysql中间件atlas配置使用

    MySQL所在机器: 192.168.16.70(Master) 192.168.16.74(Slave)      192.168.16.72(atlas)注意:主从复制需要自行配置atlas配置使 ...

  5. 字节流VS缓冲流

    ---恢复内容开始--- 字节流VS缓冲流 java.io包中的类大致可以分为:InputStream.OutputStream.Reader.Writer.InputStream/Reader可以理 ...

  6. RTMP流媒体播放过程

      RTMP协议规定:第一步,建立一个网络连接(NetConnection):客户端和服务端的基础连通关系 第二步:建立一个网络流(NetStream)发送多媒体的通道(只能建立一个网络连接,可以建立 ...

  7. Django框架

    一.首先,到底什么是框架? 想要回答这个问题,我们要慢慢来. ①首先从DRY原则开始说起 Don't Repeat Yourself,不要重复你的代码. DRY原则的重要性怎么提都不过分,很多人说编程 ...

  8. c风格字符串

    1.字符数组截取 有当然有了,应均包含在<string.h>中. 有strncpy,strncat.可以帮你从任何位置,取得任意合法长度的字符串. 用法基本同strcpy,strcat. ...

  9. 每日一记-mybatis碰到的疑惑:String类型可以传入多个参数吗

    碰到一个觉得很疑惑的问题,Mybatis的parameterType为String类型的时候,能够接收多个参数的吗? 背景 初学Mybatis的时候,看的教程和书籍上都是在说基本的数据类型如:int. ...

  10. 配置react native遇到的问题

    折腾了两天终于解决了问题,一开始用模拟器是报如下图的错 然后用真机的时候又报下图的错 这个错误网上有很多解决方法,说是要降级处理,将build.gradle中的1.3.1改成1.2.3,但是改完之后问 ...