为什么反编译.NET IL代码这么容易?

时间:2009-03-22 18:30:51

标签: .net bytecode cil decompiling intermediate-language

与反编译本机x86二进制文件相比,为什么将.NET IL-code反编译为源代码如此容易? (Reflector在大多数情况下都会生成相当好的源代码,而反编译C ++编译器的输出几乎是不可能的。)

是否因为IL包含大量元数据?或者是因为IL是比x86指令更高的抽象?我做了一些研究,发现了以下两篇有用的文章,但它们都没有回答我的问题。

4 个答案:

答案 0 :(得分:24)

我认为你已经拥有了最重要的一点。

  • 正如您所说,可用的元数据更多。我不知道C或C ++编译器发出的内容的细节,但我怀疑 IL中包含更多名称和类似信息。只需看看反编译器知道特定堆栈帧中的内容,例如 - 就x86而言,您只知道堆栈是如何使用;在IL中你知道堆栈的内容代表(或者至少是类型 - 而不是语义!)
  • 同样,正如您已经提到的,IL是比x86更高级别的抽象。 x86不知道方法或函数调用是什么,或事件,属性等.IL还包含所有信息。
  • 通常,C和C ++编译器的优化程度远远高于(比如说)C#编译器。这是因为C#编译器假设大多数优化仍可以在以后执行 - 由JIT执行。在某些方面,C#编译器而不是尝试进行大量优化是有意义的,因为JIT可以使用各种信息,但C#编译器没有。优化的代码更难以反编译,因为它远离原始源代码的自然表示。
  • IL被设计为JIT编译; x86被设计为本机执行(无可否认地通过微代码)。 JIT编译器所需的信息类似于反编译器所需的信息,因此反编译器可以更轻松地使用IL。在某些方面,这只是对第二点的重述。

答案 1 :(得分:9)

有很多事情可以让逆向工程变得相当容易。

  • 输入信息。这是巨大的。在x86汇编程序中,您必须根据变量的使用方式推断变量的类型。

  • 结构。有关应用程序结构的信息在il拆卸中更为可用。这与信息类型相结合,可为您提供大量数据。你现在处于相当高的水平(相对于x86汇编程序)。在本机汇编程序中,您必须根据数据的使用方式推断结构布局(甚至它们是结构的事实)。并非不可能,但更耗时。

  • 名。了解事物的名称可能很有用。

这些结合起来意味着你有很多关于可执行文件的数据。 Il基本上工作在比源代码更接近源的级别上。字节码工作的级别越高,一般来说,逆向工程就越容易。

答案 2 :(得分:4)

C#和IL几乎是一对一的映射。 (对于一些较新的C#3.0特性,情况就不那么好了。)映射的紧密性(以及C#编译器中缺少优化器)使得事情变得“可逆”。

答案 3 :(得分:3)

扩展Brian的正确答案

如果您认为所有IL都可以轻松解压缩,我建议编写一个非平凡的F#程序并尝试反编译该代码。 F#进行了大量的代码转换,因此实际发出的IL和原始代码库的映射非常差。恕我直言,要查看反编译的F#代码并获取原始程序要比使用C#或VB.Net要困难得多。