在本文中,将探讨.NET程序集是如何被打包进PE文件格式的。将使用一些工具来帮助分析和理解文件结构,而不是深入到每个字节的详细包装方式。
为了分析PE文件,使用了以下工具:
1.1 Hex编辑器ImHex:这是一个免费的软件,它允许给文件的不同部分上色,以便更好地理解文件结构。
1.2 PE查看器PE-bear:这是一个非常有用的工具,用于可视化地分析PE文件。虽然它不覆盖所有PE文件的变体和风格,但对于简单的PE文件来说,它是一个出色的查看器/解析器/分析器。
1.3 汇编查看器:项目中提供了一个出色的.NET汇编查看器,它是免费的。
1.4 CFF Explorer:另一个PE文件资源管理器,可以在指定的链接中找到。
在之前的中,通过PE-bear工具看到了NT头信息的“可选头 - 数据字典”部分。在文件偏移0x168处,可以看到.NET头信息位于0x2008(RVA)地址。通过计算,可以找到原始文件中的位置和大小。
在Hex编辑器中,可以看到这个信息的十六进制表示。PE-bear和汇编查看器也提供了对这个信息的解释。
资源目录位于0x2AFC(RVA),大小为0xD8。通过计算,可以找到原始文件中的位置和结束位置。在Hex编辑器中,可以看到资源目录的十六进制表示,并且可以看到如何将C#代码资源中的字符串“HW”映射到“Hello World!”。
4.1 简短的理论背景:.NET程序集中的元数据被组织在5个流中,每个流的名称都以#开头。这些流包括:
#~流:这是“元数据流”,包含程序集中的类型、方法、字段、属性和事件的信息。
#Strings流:包含命名空间、类型和成员的名称。
#US流:这是“用户字符串堆”,包含代码中使用的所有字符串。
#GUID流:存储程序集中使用的GUID。
#Blob流:包含纯二进制数据。
4.2 文件内容:在文件偏移0x210处,可以看到元数据头的位置。通过计算,可以找到元数据头在原始文件中的位置。在Hex编辑器中,可以看到元数据头的十六进制表示,而汇编查看器提供了对这个信息的解释。
通过计算,可以找到每个流在原始文件中的起始和结束位置。例如,#Strings流从0x6EC开始,到0xAFC结束。
#~流是特殊的,所以它被以不同的方式呈现。
元数据之后,方法体(即IL)在哪里?为了找到它们,需要解释元数据。将使用工具来帮助进行解释,而不是手动进行。
通过CFF Explorer,可以看到元数据流#~包含一个包含方法的文件夹。对于方法Main,可以看到起始点的偏移量是0x2069(RVA)。通过计算,可以找到原始文件中的位置。
因此,方法体存储在.NET头信息和元数据头之间。在文件中,这个区域是0x250到0x31B。