混淆的 C# 或 Java 是否比 C 更容易反编译,因为堆栈机 - 寄存器机的差异?还是有其他原因



我看到有人说,通过调用框架api(如String)来简化混淆的C#和Java的反编译。但是,这对我来说不太有意义,因为 C 程序不应该也对一些标准库进行明显的调用,这相当于 C# API?

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

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

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

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

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

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

在用于

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

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

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

相关内容

最新更新