我并不是在总体上询问逆向工程的难度,而是对特定的假设目标进行逆向工程的难度。我们假设拥有源代码不需要反向工程,因此是最简单的。与目标代码,字节码和机器码进行逆向工程比较如何?混淆将如何影响四种格式的难度?我正在寻找试图量化这些比较的答案。

评论

我的意思是根据时间复杂度(如果可能的话,平均和最差情况)进行量化。我假设执行时间是主要瓶颈。

#1 楼

恕我直言,一般来说,难易程度:


目标代码
机器代码
字节码

我的推理是这样的:

目标代码最简单,因为它通常包含许多符号或调试信息。即使没有,您也拥有一点额外的知识,因为您知道该文件中的所有代码都与一个编译对象相关。知道这一点非常有用,并有助于分析(除非它是一个巨大的整体程序)。

接下来的机器代码是最简单的,因为机器体系结构总体上定义得很好并且有很好的文档记录。您只需要一个反汇编器,代码就在您的掌握之内。

字节码在简单和超硬之间有所不同,因为它基本上可以是任何东西。字节码本身在不了解要为其编写虚拟机的情况下是无用的。例如,JVM的字节码很简单,因为我们对JVM有明确定义的规范。但是,为Themida VM生成的字节码很困难,因为它是随机的,您必须分析该特定VM,然后才能有意义地解释字节码(这本身就很困难)。

混淆几乎总是很难分析下面的代码。但这显然取决于混淆的程度。使用简单的脚本可以忽略一些琐碎的事情,可以跳过经过混淆的代码(例如垃圾邮件)来忽略某些问题,而另一些则非常复杂,需要复杂的仿真器或分步分析。如果不设计特定的多标准分析框架,很难量化这些差异。

#2 楼

只是为了从混淆的角度添加一些内容,我想通过@fileoffset添加一个很好的答案。

从源代码到生产可执行文件(可能被混淆)会丢失一些信息,并有选择地添加一些白噪声。此类信息的最简单示例是代码中的注释。噪声的最简单示例是通过PLT / GOT进行的间接调用。

此信息可以归类为:


整个程序语义,例如算法,算法执行顺序,模块,修订,注释以及所有这些与所有程序的关系,等等。在从程序到平台的本机代码的编译过程中,将删除这些信息,如果平台不执行该信息需要它(例如,Java,.NET和ActionScript并不总是这样,因为模块和类是平台底层语言的一部分,但是相反,这对于编译为ARM,IA32-64和其他真正的语言绝对正确世界处理器)。仅当可执行文件作为平台语言的一部分存在于可执行文件中时,此类信息才能被混淆破坏,而这恰恰是Java混淆器的一种工作方法。
基本算法构建块,例如循环,函数,条件表达式,结构,全局变量,对其他函数的调用,函数序言和结语,以及在函数中可以看到的几乎所有其他内容。编译会丢失此信息的重要部分,但可以从上下文中恢复。
混淆会严重破坏此类代码工件。
通过对标准任务使用创新的和非标准的模式,例如控制流更改(例如控制流展平,循环展开,不需要堆栈操作等)。请注意,此处的混淆强度取决于平台要求。
平台级别的抽象,例如寄存器,堆栈,单个指令,标志等。混淆可能会掩盖这种情况,例如,基于虚拟机的混淆器只是在动态地发明随机虚拟机。另外,大多数混淆器都添加了不需要的说明。

逆向工程是从代码中恢复丢失信息的过程,如果可能的话,从最低级别到最高级别。此过程基于对标准模式的识别。如果删除标准模式,则此过程将变得更加困难。去除/改变/损坏/模糊/白色噪声的标准结构的数量或数量级可以用作混淆强度的不完整和不良度量。不幸的是,我没有其他合理的措施。

让我们尝试从这种角度对格式进行重新分类,以消除不必要的混淆工作。


源代码
目标代码
未混淆高级.NET,ActionScript和Java等知名平台的生产代码
混淆的生产代码适用于.NET,ActionScript和Java等高级知名平台
没有混淆的本机代码
没有像Themida这样的VM就混淆了本机代码
像Themida那样的VM混淆了VM

最好的(和最有趣的)启发式检查和证明上面的顺序是针对相应平台的反编译器(它是自动逆向工程工具)的成本,其存在和质量。

例如一些Java反编译器可以执行自动部分反混淆处理,并且几乎总是可以在类方法级别上以许可证$ 0的价格重建代码。

相反,本机代码反编译要么运行不充分(它们都无法达到JAD的质量,非常老的Java反编译器),要么成本很高,例如Hex Rays反编译器,我知道的唯一稳定的工作反编译器(我尝试过

顺便说一句,有一些文章试图测量混淆强度,例如这样的文章(该文章对于现实生活中的二进制文件几乎没有用,但是其中的列表参考很有趣)。我所知道的这些工具中,没有一个可以使用合理大小的被测可执行文件。他们中的大多数人都在不切实际的假设下工作和/或利用特定的混淆算法缺陷。