为什么不能创建一个能够像Java和C#那样准确运行的C ++反编译器?
答案 0 :(得分:9)
有几个原因:
内联。很多C ++代码都在优化的构建中内联。这对任何形式的反编译都会造成严重破坏。要弄清楚函数是内联的,反编译器必须分析内联代码的细节并将它们匹配起来。后内联优化步骤可以使代码变得非常不同,具体取决于内联的位置。
模板。模板仅使用#1,但它们会产生其他问题。至少在理论上,在两个地方内联的函数将编译为相同的汇编指令序列。但对于使用不同模板参数实例化的模板代码?不同的实例化通常必须编译成不同的指令序列。这变得更加困难,因为模板代码可以根据模板参数调用不同的函数集。这些功能本身可以内联。
编译时执行。模板元编程允许编译器实际执行代码。但是C ++ 11的constexpr
提供了一种在编译时进行一些计算的更自然的方法。显然,编译时函数调用或元函数实例化不能成为已编译可执行文件的一部分。只有他们的结果将是(因为那有点重要)。
缺乏全面的运行时反射。 C#和Java都使用大量有关原始源代码性质的信息来保护它们的字节码。对象定义很容易检测,对象名称,成员变量类型和名称等也是如此.C ++编译为机器语言,不需要任何此类信息。由于不需要,编译器不会生成它。甚至ISO C ++委员会的反思研究小组也专注于编译时反射,这是在运行时无法获得的信息。
即使std::type_info
也没有提供任何内容。原因是,如果编译器没有检测到特定类型将调用typeid
,则编译器不需要为其生成std::type_info
对象。即使它确实如此,所有给你的东西都是一个对象的名字(和一个标识符)。没有更多。
答案 1 :(得分:4)
因为C ++编译器通常不会将任何更多信息放入可执行文件中(特别是如果它们是在发布模式而不是调试版本中编译),所以您需要准确反编译程序所需的信息根本不存在于可执行文件中。
当然可以制作C ++编译器,其中包含可执行文件中的所有必要信息(例如,在最天真的实现中,它可以简单地在可执行文件中包含源代码本身的副本),但这样做会使可执行文件变得更大,并且大多数非开源C ++开发人员更希望其他人不能够反编译可执行文件,因此对该功能没有太多需求。 / p>