为什么拆分原生Win32图像(例如用C / C ++构建)比拆解.NET应用程序难度更高?
主要原因是什么?因为什么?
答案 0 :(得分:16)
.net程序集内置于Common Intermediate Language。在CLR将其编译为在适当的系统上运行时,它将被编译,直到它即将被执行。 CIL具有大量元数据,因此可以将其编译到不同的处理器体系结构和不同的操作系统上(在Linux上,使用Mono)。这些类和方法基本保持不变。
.net还允许反射,这需要将元数据存储在二进制文件中。
C和C ++代码在编译时编译为选定的处理器体系结构和系统。为Windows编译的可执行文件在Linux上不起作用,反之亦然。 C或C ++编译器的输出是汇编指令。源代码中的函数可能不作为二进制函数存在,而是以某种方式进行优化。编译器还可以拥有相当激进的优化器,它们将采用逻辑结构化代码并使其看起来非常不同。代码将更有效(在时间或空间上),但可能使其更难以逆转。
答案 1 :(得分:14)
由于.NET的实现允许通过CLI和CLR在C#,VB甚至C / C ++等语言之间实现互操作,这意味着必须将额外的元数据放入目标文件中以正确传输类和对象属性。这使得更容易反汇编,因为二进制对象仍然包含该信息,而C / C ++可以抛弃该信息,因为它不是必需的(至少对于代码的执行,当然在编译时仍需要信息)。
此信息通常仅限于与课程相关的字段和对象。堆栈上分配的变量可能在发布版本中没有注释,因为互操作性不需要它们的信息。
答案 2 :(得分:6)
另一个原因 - 大多数C ++编译器在生成最终二进制文件时执行的优化不会在IL级别上针对托管代码执行。
结果,像容器上的迭代这样的东西看起来就像本地代码的成员inc
/ jnc
汇编指令相比,IL中有意义名称的函数调用。由于JIT编译器会内联一些类似于本机编译器的调用,因此生成的执行代码可能相同(或至少接近),但在CLR版本中,可以看到的代码更具可读性。
答案 3 :(得分:4)
人们提到了一些原因;我会提到另一个,假设我们正在谈论反汇编而不是反编译。
x86代码的问题在于区分代码和数据非常困难并且容易出错。反汇编者必须依靠猜测才能做到正确,他们几乎总是会错过一些东西;相比之下,中间语言被设计被“反汇编”(因此JIT编译器可以将“反汇编”转换为机器代码),因此它们不包含您在机器代码中找到的歧义。最终结果是反编译IL代码非常简单。
如果你在谈论反编译,那就不一样了;它与(大多数).NET应用程序缺乏优化有关。大多数优化都是由JIT编译器而不是C#/ VB.NET /等完成的。编译器,因此汇编代码几乎是源代码的1:1匹配,因此找出原始代码是非常有可能的。但是对于原生代码来说,有一百万种不同的方法来翻译少数源代码行(哎呀,即使是无操作系统也有不同的编写方式,具有不同的性能特征!)因此很难弄清楚原始内容是什么
答案 4 :(得分:1)
一般情况下,反汇编C ++和.NET代码没有太大区别。因为C ++更难以反汇编,因为它做了更多的优化和类似的东西,但这不是主要问题。
主要问题是名字。反汇编的C ++代码将包含名为A,B,C,D,... A1等的所有内容。除非您能够识别出这种格式的算法,否则您可以从反汇编的C ++二进制文件中提取的信息不多。 / p>
另一侧的.NET库包含方法,方法参数,类名和类字段名称。它使得对反汇编代码的理解变得更加容易。所有其他的东西都是次要的。
答案 5 :(得分:1)
除了元数据之外,其他答案还指出了调试信息和所有技术原因;我的想法是:
您认为反汇编win32
图片的主要原因比.Net
计划更困难,因为人性观点。
从机器的角度来看,本机代码更加透明,甚至是逆向工程的处理。
相反,我想说要反汇编.Net
应用程序/库 CAN 更难,如果代码已被混淆。
您可能认为反汇编本地win32
程序很困难,因为它的性质是由机器代码组成的。但实际上,通过物理世界和心理学的类比,我认为机器代码更像是物理代码 - 它会影响实际的功能。虽然win32
程序的逆向工程可能非常复杂,但代码属于CPU指令集的范围。最复杂的可能是:
.Net
有一些混淆器和去混淆器,用不同的技术实现。 完全有可能使.Net
个应用程序比win32
程序更难分解。由于大多数基于虚拟机的程序更容易被反汇编,我认为有以下考虑因素不能太混淆:
如果您已经阅读了OpCodes
.Net
框架的Reflection.Emit
代码,并且您意识到语言级别和OOP的概念更复杂。例如,使用MSIL(CIL)
,您可以发出调用构造函数,方法或虚方法的操作码。是的,它基于CLR
并由{{1}}运行;但这并不意味着拆卸起来更容易;它可以以混淆的方式制作,并且变得更难以与源代码相反;像精神世界总是比物质世界更难以理解。