我们通过csc工具可以把一个cs代码文件编译成一个.exe文件, 大家都知道,这个文件在任何装有Windows的计算机上都可以被加载和运行, 最近学.NET框架也有一段时间了, 为了对所学习的知识进行复习和梳理, 在此做一些笔记。今天就说一下PE文件.
比如有这样一个代码文件(控制台运用程序):App.cs
using System;
namespace App
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
class App
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
System.Console.Write("Hello Word");
}
}
}
便宜后产生一个App.exe文件,下面就这个文件为例对他进行分析:
首先一个PE文件包含4个部分:PE表头,CLR表头,元数据,IL代码.PE表头存放了Windows操作系统要求的标准信息, CLR表头是托管模块专用的, 他包含了元数据的版本信息, 以及一个标识入口点方法的MethodDef标记, 以及一个可选的强名称数字签名.以及一些元数据的其他信息(如偏移量).
我们先用VS自带的IL反汇编器对App.exe进行反汇编来查看元数据信息, 命令为ILDasm.exe /adv app.exe
ScopeName : App.exe
MVID : {6AB1FC55-57E4-4FD4-807C-4578758AF207}
===========================================================
Global functions
-------------------------------------------------------
Global fields
-------------------------------------------------------
Global MemberRefs
-------------------------------------------------------
TypeDef #1
-------------------------------------------------------
TypDefName: App.App (02000002)
Flags : [NotPublic] [AutoLayout] [Class] [AnsiClass] (00100000)
Extends : 01000001 [TypeRef] System.Object
Method #1 [ENTRYPOINT]
-------------------------------------------------------
MethodName: Main (06000001)
Flags : [Private] [Static] [HideBySig] [ReuseSlot] (00000091)
RVA : 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
ReturnType: Void
1 Arguments
Argument #1: SZArray String
1 Parameters
(1) ParamToken : (08000001) Name : args flags: [none] (00000000)
CustomAttribute #1 (0c000001)
-------------------------------------------------------
CustomAttribute Type: 0a00000e
CustomAttributeName: System.STAThreadAttribute :: instance void .ctor()
Length: 4
Value : 01 00 00 00 > <
ctor args: ()
Method #2
-------------------------------------------------------
MethodName: .ctor (06000002)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886)
RVA : 0x00002068
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #1 (01000001)
-------------------------------------------------------
Token: 0x01000001
ResolutionScope: 0x23000001
TypeRefName: System.Object
MemberRef #1
-------------------------------------------------------
Member: (0a000010) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #2 (01000002)
-------------------------------------------------------
Token: 0x01000002
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyKeyNameAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000001) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #3 (01000003)
-------------------------------------------------------
Token: 0x01000003
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyKeyFileAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000002) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #4 (01000004)
-------------------------------------------------------
Token: 0x01000004
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyDelaySignAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000003) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: Boolean
TypeRef #5 (01000005)
-------------------------------------------------------
Token: 0x01000005
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyVersionAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000004) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #6 (01000006)
-------------------------------------------------------
Token: 0x01000006
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyCultureAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000005) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #7 (01000007)
-------------------------------------------------------
Token: 0x01000007
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyTrademarkAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000006) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #8 (01000008)
-------------------------------------------------------
Token: 0x01000008
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyCopyrightAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000007) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #9 (01000009)
-------------------------------------------------------
Token: 0x01000009
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyProductAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000008) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #10 (0100000a)
-------------------------------------------------------
Token: 0x0100000a
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyCompanyAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a000009) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #11 (0100000b)
-------------------------------------------------------
Token: 0x0100000b
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyConfigurationAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a00000a) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #12 (0100000c)
-------------------------------------------------------
Token: 0x0100000c
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyDescriptionAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a00000b) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #13 (0100000d)
-------------------------------------------------------
Token: 0x0100000d
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyTitleAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a00000c) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #14 (0100000e)
-------------------------------------------------------
Token: 0x0100000e
ResolutionScope: 0x23000001
TypeRefName: System.Diagnostics.DebuggableAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a00000d) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
2 Arguments
Argument #1: Boolean
Argument #2: Boolean
TypeRef #15 (0100000f)
-------------------------------------------------------
Token: 0x0100000f
ResolutionScope: 0x23000001
TypeRefName: System.STAThreadAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a00000e) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #16 (01000010)
-------------------------------------------------------
Token: 0x01000010
ResolutionScope: 0x23000001
TypeRefName: System.Console
MemberRef #1
-------------------------------------------------------
Member: (0a00000f) Write:
CallCnvntn: [DEFAULT]
ReturnType: Void
1 Arguments
Argument #1: String
Assembly
-------------------------------------------------------
Token: 0x20000001
Name : App
Public Key :
Hash Algorithm : 0x00008004
Major Version: 0x00000001
Minor Version: 0x00000000
Build Number: 0x0000095c
Revision Number: 0x00009f6c
Locale: <null>
Flags : [SideBySideCompatible] (00000000)
CustomAttribute #1 (0c000002)
-------------------------------------------------------
CustomAttribute Type: 0a000007
CustomAttributeName: System.Reflection.AssemblyCopyrightAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #2 (0c000003)
-------------------------------------------------------
CustomAttribute Type: 0a000002
CustomAttributeName: System.Reflection.AssemblyKeyFileAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #3 (0c000004)
-------------------------------------------------------
CustomAttribute Type: 0a000003
CustomAttributeName: System.Reflection.AssemblyDelaySignAttribute :: instance void .ctor(bool)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ( <can not decode> )
CustomAttribute #4 (0c000005)
-------------------------------------------------------
CustomAttribute Type: 0a000006
CustomAttributeName: System.Reflection.AssemblyTrademarkAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #5 (0c000006)
-------------------------------------------------------
CustomAttribute Type: 0a000001
CustomAttributeName: System.Reflection.AssemblyKeyNameAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #6 (0c000007)
-------------------------------------------------------
CustomAttribute Type: 0a000008
CustomAttributeName: System.Reflection.AssemblyProductAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #7 (0c000008)
-------------------------------------------------------
CustomAttribute Type: 0a000009
CustomAttributeName: System.Reflection.AssemblyCompanyAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #8 (0c000009)
-------------------------------------------------------
CustomAttribute Type: 0a00000a
CustomAttributeName: System.Reflection.AssemblyConfigurationAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #9 (0c00000a)
-------------------------------------------------------
CustomAttribute Type: 0a00000b
CustomAttributeName: System.Reflection.AssemblyDescriptionAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #10 (0c00000b)
-------------------------------------------------------
CustomAttribute Type: 0a00000c
CustomAttributeName: System.Reflection.AssemblyTitleAttribute :: instance void .ctor(class System.String)
Length: 5
Value : 01 00 00 00 00 > <
ctor args: ("")
CustomAttribute #11 (0c00000c)
-------------------------------------------------------
CustomAttribute Type: 0a00000d
CustomAttributeName: System.Diagnostics.DebuggableAttribute :: instance void .ctor(bool,bool)
Length: 6
Value : 01 00 01 01 00 00 > <
ctor args: ( <can not decode> )
AssemblyRef #1
-------------------------------------------------------
Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Major Version: 0x00000001
Minor Version: 0x00000000
Build Number: 0x00001388
Revision Number: 0x00000000
Locale: <null>
HashValue Blob:
Flags: [none] (00000000)
User Strings
-------------------------------------------------------
70000001 : (10) L"Hello Word"
上面是反汇编后我们看到的元数据信息:
ScopeName : App.exe
MVID : {6AB1FC55-57E4-4FD4-807C-4578758AF207}
===========================================================
Global functions
-------------------------------------------------------
Global fields
-------------------------------------------------------
Global MemberRefs
-------------------------------------------------------
以上显示的部分是模块定义表, 这个表中包含一个标识托管模块的条目. 该条目包含了一个有编译器创建的模块版本ID(MVID : {6AB1FC55-57E4-4FD4-807C-4578758AF207}), 一个文件名(ScopeName : App.exe). 版本ID的存在使得我们在重命名文件时可以保留原来的名称记录.
TypeRef #11 (0100000b)
-------------------------------------------------------
Token: 0x0100000b
ResolutionScope: 0x23000001
TypeRefName: System.Reflection.AssemblyConfigurationAttribute
MemberRef #1
-------------------------------------------------------
Member: (0a00000a) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
上面所示的带有TypeRef标记的节表示一个类型定义表, 我们编译得到的托管模块中的每一个类型都映射到一个类型定义表. 如上的类型定义表表示AssemblyInfo.cs文件中引用到的类型System.Reflection.AssemblyConfigurationAttribute, 可以看到他是一个特性类, 返回值为空, 可以带一个string类型的参数.还含有一个构造器( .ctor). 另外一个托管模块还可能包含引用表. 定表还可能有方法定义表,属性定义表, 字段定义表, 参数定义表, 事件定义表等. 引用表又可能包含程序集引用表, 模块引用表, 类型引用表等.
程序集引用表示例:
AssemblyRef #1
-------------------------------------------------------
Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Major Version: 0x00000001
Minor Version: 0x00000000
Build Number: 0x00001388
Revision Number: 0x00000000
Locale: <null>
HashValue Blob:
Flags: [none] (00000000)
用IL工具打开统计视图我们可以看到:
File size : 16384
PE header size : 4096 (496 used) (25.00%)
PE additional info : 2255 (13.76%)
Num.of PE sections : 3
CLR header size : 72 ( 0.44%)
CLR meta-data size : 1116 ( 6.81%)
CLR additional info : 0 ( 0.00%)
CLR method headers : 24 ( 0.15%)
Managed code : 18 ( 0.11%)
Data : 2132 (13.01%)
Unaccounted : 6671 (40.72%)
Num.of PE sections : 3
.text - 4096
.rsrc - 4096
.reloc - 4096
CLR meta-data size : 1116
Module - 1 (10 bytes)
TypeDef - 2 (28 bytes) 0 interfaces, 0 explicit layout
TypeRef - 16 (96 bytes)
MethodDef - 2 (28 bytes) 0 abstract, 0 native, 2 bodies
MemberRef - 16 (96 bytes)
ParamDef - 1 (6 bytes)
CustomAttribute- 12 (72 bytes)
Assembly - 1 (22 bytes)
AssemblyRef - 1 (20 bytes)
Strings - 465 bytes
Blobs - 60 bytes
UserStrings - 24 bytes
Guids - 16 bytes
Uncategorized - 173 bytes
CLR method headers : 24
Num.of method bodies - 2
Num.of fat headers - 2
Num.of tiny headers - 0
Managed code : 18
Ave method size - 9
这些信息包括文件的大小, 文件各组成部分的大小和在文件中所占的比率.掌握了这些信息我们可以更清晰的看到PE文件元数据的结构了.然而MS提供了这样简单的对.NET程序反汇编的途径不得我不让我们对程序集安全担心, 我们可以通过第三方提供的混淆器之类的工具对我们的程序集进行保护, 但是大多数情况是不必要的,因为一些敏感的程序往往被部署到WebServices或者公司服务器上, 既然拿不到程序集反汇编也就无从谈起了.
最后建议大家多运用IL工具, 对了解PE文件的结构有很多的帮助.