MSIL探索-IL介绍

by  zguosir/gshzheng

 

1.

我们用C#,Vb.Net,Asp.Net或其它的与.Net兼容的语言写的代码最终都会编译成IL。如,我们用Cobol写的程序,可以在C#中修改,然后在Asp.Net中使用。因此,理解IL是我们理解.Net相关技术的最好的方式。

 

假设您已经至少熟悉一种.Net语言,让我们一步一步揭开IL的面纱,

a1.il

.assembly zzz{}

.method static void mymethod()

{

.entrypoint

ldstr “Hello”

call void [mscorlib]System.Console::WriteLine(string)

ret

}

 

Output

hello

这是比较简单的IL程序,必须指定伪指令.assembly .entrypoint,以及ret函数结束指令。(注,译者还很老土,用的环境Net1.1Net2.0会很不一样,但我们没必要在版本上做更多的计较)

 

.开始的语句,我们称之伪指令(derective,如创建一类或方法的指令;

不以.开始的语句,是真正的汇编指令。

 

IL中,首先被执行的第一个函数为入口函数(entrypoint function,一个程序只能有一个入口函数,.entrypoint是伪指令,它的位置可以放在函数开始处,也可以放在函数的结束处。

 

ret指令表示函数代码的结束,不能省略。

 

call语句是函数调用指令,指令的调用有如下的细节

l           返回值(void

l           引用的外部装配件([mscorlib]

l           命名空间(System

l           类(Console

l           方法名称(WriteLine

l           方法参数类型(string

 

2.

下面是一个稍微复杂一点IL程序,其中引入了类的定义

a2.il

.assembly zzz{}

.class private auto ansi zzz extends [mscorlib]System.Object

{

.method public hidebysig static void mymethod() il managed

{

.entrypoint

ldstr "Hello"

call void [mscorlib]System.Console::WriteLine(string)

ret

}

}

 

 

OutPut

Hello

 

伪指令.class定义了一个类,并且有三个修饰词

l           private: 表示对类的程序的访问只能限制在当前类内部。

l           auto: 表示类在内存中的存储只有在运行时才能决定。

l           ansi: 原代码可以被分割为两部分,受控的和非受控的。

l           il managed: 暂不说明。

 

伪指令.method的修饰词

l           public: 方法的访问级别。

l           hidebysig: 此属性让父类的这个方法对派生类来说是隐藏的。

l           static: 静态的方法是属于类而不是属于对象的。标记为entrypoint的方法首先是static的。

 

3.

下面一个再复杂一点的程序,填加了更多的伪指令,还有类的构造函数的写法

a3.il

.module a3.exe

.subsystem 3

.corflags 1

.assembly extern mscorlib

{

  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..

  .ver 1:0:5000:0

}

.assembly a3

{

    .hash algorithm 0x00008004

    .ver 0:0:0:0

}

.class private auto ansi zzz extends [mscorlib]System.Object

{

.method public hidebysig static void mymethod() il managed

{

.entrypoint

ldstr "Hello"

call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String)

ret

}

 

.method public hidebysig specialname rtspecialname instance void .ctor() il managed

{

.maxstack 8

ldstr "Hello1"

call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String)

ldarg.0

call instance void [mscorlib]System.Object::.ctor()

ret

}

}

 

Output

Hello

 

.ctor: ctor就是constructor

 

rtspecialname: 这个属性告诉运行时(runtime)当前函数有个特殊的名字,应该进行某些特殊的对待。

 

Specialname: 这是通知编译器,当前函数是特殊的,RT可能忽略这个属性。

 

Instance: 指明函数调用是一个相对于实例的调用。

 

ldarg.0 一般是取的在执行堆栈上的this指针或第0个参数的地址(对于静态方法)。

 

.maxstack:指定当方法被执行时,在stack上的最大元素数

 

.module:所有的IL文件必须是某个module的一部分,这里module的名字未必与exe的名字相同。

 

.subsystem: 这个伪指令用来指定程序将要在哪个OS上运行,它也是指定运行程序类型的一种方式。下面是值的含义:

       2- Windows 控制台程序

       3- WinForm程序

       5- OS/2

 

.corflags: 1表示可执行程序,4表示类库

 

.assembly 我们创建的所有东西都是manifest的一部分,assembly伪指令是manifest的开始指令,manifest包括module,一个module只能包含一个assembly伪指令。如果exe程序,assembly只必须有的,而对于dll类库来说,它是可以缺省的。在assembly伪指令中,包含着其它的伪指令。

.hash: 指明assemblyhash代码。

.ver:  指明assembly的版本表示,它有4部分组成,有冒号分割,依次分别表示主版本号、次版本号、内建build号,修正号。

 

extern:如果需要引用其它的assemblies,就需要用到extern伪指令。

originator:这个伪指令揭示了dll创建着的唯一标识,它是创建者公钥(public key)的8位数字,显然是个hash code

 

4.

现在,我们把一个最简单的c#程序,反编译成il后,再来看程序,就貌似不怎么陌生了。

 

a4.cs

public class a4

{

    public static void Main()

    {

        System.Console.WriteLine("Hello"); 

    }  

}

 

>csc a4.cs

>ildasm a4.exe /out=a4.il

 

 

a4.il

//  Microsoft (R) .NET Framework IL Disassembler.  Version 1.1.4322.573

//  Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

 

.assembly extern mscorlib

{

  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..

  .ver 1:0:5000:0

}

.assembly a4

{

  // --- 下列自定义属性会自动添加,不要取消注释 -------

  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool,

  //                                                                                bool) = ( 01 00 00 01 00 00 )

  .hash algorithm 0x00008004

  .ver 0:0:0:0

}

.module a4.exe

// MVID: {6E8E5294-3C87-4895-BA7E-F4BDF4FEAC50}

.imagebase 0x00400000

.subsystem 0x00000003

.file alignment 512

.corflags 0x00000001

// Image base: 0x00da0000

//

// ============== CLASS STRUCTURE DECLARATION ==================

//

.class public auto ansi beforefieldinit a4

       extends [mscorlib]System.Object

{

} // end of class a4

 

 

// =============================================================

 

 

// =============== GLOBAL FIELDS AND METHODS ===================

 

 

// =============================================================

 

 

// =============== CLASS MEMBERS DECLARATION ===================

//   note that class flags, 'extends' and 'implements' clauses

//          are provided here for information only

 

.class public auto ansi beforefieldinit a4

       extends [mscorlib]System.Object

{

  .method public hidebysig static void  Main() cil managed

  {

    .entrypoint

    // 代码大小       11 (0xb)

    .maxstack  1

    IL_0000:  ldstr      "Hello"

    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)

    IL_000a:  ret

  } // end of method a4::Main

 

  .method public hidebysig specialname rtspecialname

          instance void  .ctor() cil managed

  {

    // 代码大小       7 (0x7)

    .maxstack  1

    IL_0000:  ldarg.0

    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()

    IL_0006:  ret

  } // end of method a4::.ctor

 

} // end of class a4

 

 

// =============================================================

 

//*********** 反汇编完成 ***********************

// WARNING: Created Win32 resource file a4.res