4

我已经看到它说通过对框架 api 的调用(如对字符串)的存在简化了混淆 C# 和 Java 的反编译。但是,这对我来说不太有意义,因为 C 程序不应该也对某些标准库有明显的调用,这相当于 C# api?

我还看到它说注册机(将从 C 运行程序集的硬件)和堆栈机(将运行字节码的虚拟机)之间的区别对反编译的复杂性很重要。

那么堆栈/注册机问题是这里的主要问题吗?假设如果 CLR 虚拟机被重新实现为注册机,C# 字节码会突然变得像 C 可执行文件一样难以反编译吗?或者是否还有其他一些主要的复杂性差异在这样的平台大修中不会消失?

4

3 回答 3

7

堆栈和寄存器机器之间没有区别,从两种表示中解构表达式树相对容易。

.NET 和 JVM 很容易反编译,主要是因为元数据:类型和方法名称等。

使用剥离的本机可执行文件,您将获得所有乐趣:没有有意义的函数名称,没有明确的数据类型,内联代码的加载(然后被进一步优化严重破坏)代码,展开的循环,不可约化的控制流,展开的尾部通话等

在字节码中,大多数此类优化尚未完成(将它们留给 JIT),因此与删除元数据并应用优化相比,它更接近原始源。无论如何,堆栈机器、基于寄存器的、线程化的 Forth 代码或其他任何东西。

于 2012-05-10T12:31:45.830 回答
3

在用于真实硬件的机器代码中,您并不总是知道代码在内存中的哪个位置开始。由于 x86 指令的长度可变,这会使反汇编程序解码具有错误偏移量的指令。指针算术的可能性也无济于事。在 .NET IL 和 java 操作码中,代码开始和结束的位置总是很清楚,并且不允许任意指针算术。因此,即使生成的汇编代码不易辨认,反汇编也是 100% 准确的。对于真正的机器代码,至少在 x86 上,除非您运行程序,否则您永远不会知道确切的控制流和代码入口点,即使您假设没有代码变形。

于 2012-05-10T12:33:34.750 回答
1

从易于逆向工程的角度比较 C++ 和 Java,请阅读我文章的介绍部分。(您可以阅读“C#”而不是“Java”和“CLR”而不是“JVM”:))

至于对 C 标准库的调用,如果静态链接它们,二进制文件中将没有库函数名称。此外,C++ 编译器将内联头文件中定义的小方法,更不用说它将对模板做什么......

于 2012-06-03T09:23:48.743 回答