与反编译本机 x86 二进制文件相比,为什么将 .NET IL 代码反编译为源代码如此容易?(Reflector 大部分时间都产生了相当不错的源代码,而反编译 C++ 编译器的输出几乎是不可能的。)
是因为 IL 包含很多元数据吗?还是因为 IL 是比 x86 指令更高的抽象?我做了一些研究,发现了以下两篇有用的文章,但它们都没有回答我的问题。
与反编译本机 x86 二进制文件相比,为什么将 .NET IL 代码反编译为源代码如此容易?(Reflector 大部分时间都产生了相当不错的源代码,而反编译 C++ 编译器的输出几乎是不可能的。)
是因为 IL 包含很多元数据吗?还是因为 IL 是比 x86 指令更高的抽象?我做了一些研究,发现了以下两篇有用的文章,但它们都没有回答我的问题。
我想你已经掌握了最重要的部分。
有很多事情可以让逆向工程变得相当容易。
类型信息。这是巨大的。在 x86 汇编器中,您必须根据变量的使用方式来推断变量的类型。
结构体。有关应用程序结构的信息在 il disassemblies 中提供更多信息。这与类型信息相结合,为您提供了惊人的数据量。此时您的工作水平相当高(相对于 x86 汇编器)。在本机汇编程序中,您必须根据数据的使用方式来推断结构布局(甚至它们是结构的事实)。并非不可能,但更耗时。
名字。知道事物的名称可能很有用。
这些东西结合起来,意味着你有很多关于可执行文件的数据。与本机代码的编译器相比,Il 基本上在更接近源代码的水平上工作。一般来说,字节码工作的级别越高,逆向工程就越容易。
C# 和 IL 几乎是一对一的映射。(对于一些较新的 C# 3.0 功能,情况就不那么好了。)映射的紧密性(以及 C# 编译器中缺少优化器)使得事情变得如此“可逆”。
扩展布赖恩的正确答案
如果您认为所有 IL 都很容易反编译,我建议您编写一个重要的 F# 程序并尝试反编译该代码。F# 做了很多代码转换,因此从实际发出的 IL 和原始代码库的映射非常差。恕我直言,与 C# 或 VB.Net 相比,查看反编译的 F# 代码并取回原始程序要困难得多。