VS2017 中 ILDASM的使用

2019-02-22  本文已影响0人  kalanliao

IL是微软平台上的一门中间语言,我们常写的C#代码在编译器中都会自动转换成IL,然后在由即时编译器(JIT Compiler)转化机器码,最后被CPU执行。ildasm.exe反编译工具将IL汇编成可跨平台可执行的(pe)文件。可供我们了解别人代码和修改。有了他我们看待问题可以不用停留在编辑器层面,可深入中间层。

  1. 第一步 安装

首先安装完VS2017之后,在我们的系统中找到我们的ildasm.exe程序的地址,一般在系统中的地址为:
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe

  1. 第二步 添加
图片.png

在VS2017顶部操作栏目的工具里面,我们找到外部工具点击打开


图片.png

我们在命令的部分输入我们说的ildasm.exe的地址,其他按照我们图中所示的填写,点击确定,保存为自定义外部工具。

  1. 第三步 使用


    图片.png

我们返回外面的工具中,可以看到出现了我们刚才添加的外部工具。


图片.png

我们点击查看IL


我们已经可以查看自己程序的IL了

  1. 第四步 读懂
    我们尝试读懂IL,当我们遇到一些在编辑层无法看透的问题时候,我们可以尝试通过IL里面来查看程序的问题。下面我提供一份IL类型图:


    图片.png

如下面这段IL


图片.png
MANIFEST:是一个附加信息列表,主要包含程序集的一些属性,如程序集名称、版本号、哈希算法等;
Democode:项目名称
Democodeing.Common:命名空间
Democodeing.ICar:接口
Democodeing.Program:类,主要查看存类下面的内容。
如这段代码中
.class private auto ansi beforefieldinit DemoCoding.Program
       extends [mscorlib]System.Object
{
} // end of class DemoCoding.Program
1).class,表示Program是一个类。并且它继承自程序集—mscorlib的System.Object类;
2)private,表示访问权限;
3)auto,表示程序的内存加载全部由CLR来控制;
4)ansi,是为了在没有托管代码与托管代码之间实现无缝转换。这里主要指C、C++代码等;
5)beforefieldinit,是用来标记运行库(CLR)可以在静态字段方法生成后的任意时刻,来加载构造器(构造函数);

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // 代码大小       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ret
} // end of method Program::.ctor

1)cil managed:表示其中为IL代码,指示编译器编译为托管代码;
2).maxstack:表示调用构造函数.otor期间的评估堆栈(Evaluation Stack) ;
3)  IL_0000:标记代码行开头;
4)ldarg.0:表示转载第一个成员参数,在实例方法中指的是当前实例的引用;
5)call:call一般用于调用静态方法,因为静态方法是在编译期就确定的。而这里的构造函数.otor()也是在编译期就制定的。而另一指令callvirt则表示调用实例方法, 它是在运行时确定的,因为如前述,当调用方法的继承关系时,就要比较基类与派生类的同名函数的实现方法(virtual和new),以确定调用的函数所属的Method Table;
6)ret:表示执行完毕,返回;
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代码大小       19 (0x13)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Hello World"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  call       string [mscorlib]System.Console::ReadLine()
  IL_0011:  pop
  IL_0012:  ret
} // end of method Program::Main
1) hidebysig:表示当把此类作为基类,存在派生类时,此方法不被继承,同上构造函数;
2).entrypoint:指令表示CLR加载程序时,是首先从.entrypoint开始的,即从Main方法作为程序的入口函数;
3)nop:为空该指令,主要给外部设备或者指令间隙准备时间;
4)ldstr:创建String对象变量"Hello World." ;
5)pop:取出栈顶的值。当我们不需要把值存入变量时使用;
  1. 第五步 修改

我们先写一个最简单的


图片.png

这一段比较简单也比较容易理解,编译之后IL为


图片.png

我们利用工具双击打开Main方法

图片.png

我们修改代码
文件-->转储。确定后选择另存路径,会生成二个文件:*.il 和 *.res

图片.png 图片.png

打开.il文件


图片.png

找到我们刚才写的输出hello word的代码块


图片.png

修改输出


图片.png
  1. 第六步 编译

我们先打开VS 2017的开发人员命令提示符

图片.png

然后输入
ilasm /exe /output=C:\Demo.exe /Resource=D:\5\1.res D:\5\1.il

图片.png

我们看到完成信息之后
在C盘找到了我们编译的EXE文件,执行

图片.png
  1. 第七步 从IL理解装箱拆箱
    我们先写一段最简单的装箱拆箱代码如下


    图片.png

用我之前教你的方法查看程序的IL


图片.png

打开我们的main方法


图片.png
我们看到IL里面表示装箱拆箱两个命令是用box和unbox,非常好理解吧

END

上一篇下一篇

猜你喜欢

热点阅读