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

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

有帮助吗?

解决方案

我认为你已经掌握了最重要的部分。

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

其他提示

有很多因素使得逆向工程变得相当容易。

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

  • 结构。有关应用程序结构的信息在 il 反汇编中更容易获得。这与类型信息相结合,为您提供了大量数据。此时您的工作水平相当高(相对于 x86 汇编程序)。在本机汇编器中,您必须根据数据的使用方式推断结构布局(甚至它们是结构的事实)。并非不可能,但要花费更多时间。

  • 名称。知道事物的名称很有用。

这些东西结合起来,意味着您拥有大量有关可执行文件的数据。Il 基本上工作在比本机代码编译器更接近源代码的级别。一般来说,字节码工作的级别越高,逆向工程就越容易。

C# 和 IL 几乎是一一对应的。(对于一些较新的 C# 3.0 功能来说,情况就不那么严重了。)映射的紧密性(以及 C# 编译器中缺乏优化器)使得事情变得如此“可逆”。

扩展布莱恩的正确答案

如果您认为所有 IL 都很容易反编译,我建议编写一个重要的 F# 程序并尝试反编译该代码。F# 进行了大量代码转换,因此实际发出的 IL 和原始代码库之间的映射非常差。恕我直言,查看反编译的 F# 代码并恢复原始程序比 C# 或 VB.Net 困难得多。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top