登录

  • 登录
  • 忘记密码?点击找回

注册

  • 获取手机验证码 60
  • 注册

找回密码

  • 获取手机验证码60
  • 找回
毕业论文网 > 外文翻译 > 理工学类 > 信息与计算科学 > 正文

Java编程语言反编译能力分析外文翻译资料

 2022-12-19 17:32:46  

英语原文共 9 页,剩余内容已隐藏,支付完成后下载完整资料


Java编程语言反编译能力分析

康斯坦丁·古斯塔罗夫斯

里加技术大学,里加,拉脱维亚

摘要——除了新的工件开发,软件工程还包括其他任务.其中一个任务是二进制工件的逆向工程.这个任务可以通过使用特殊的“反编译”软件来执行.在本文中,作者根据个人经验和软件开发人员调查的结果,对四种不同的Java编程语言反编译器进行了比较.

关键词-反编译,Java,逆向工程

1.引言

软件开发通常是产生新的工件,例如,将用某种编程语言编写的代码转换为二进制分布,有时需要执行反向操作,即逆向工程[1].逆向工程是从任何人造事物中提取知识或设计蓝图的过程.与软件工程相关,它可以描述为从二进制(编译)文件中提取源代码.虽然初看这样的过程似乎与版权冲突,但有时有必要执行这样的操作.例如,修复某个公司在一段时间前开发的程序或库中的缺陷时,但缺少该程序或库的任何源代码,这个过程可能就是必要.软件逆向工程的另一个方面可能是需要从没有源代码的库/程序中获取一些信息,例如,密码学密钥等.基本上,这些与自己产品的逆向工程相关的案例都是有效且合法的用例.一个有效的逆向工程应用程序的另一个例子是反病毒软件的作者对计算机病毒的研究[1],这对于理解恶意软件如何工作以及如何对抗它是必要的.

基于TIOBE索引[2],企业开发中最流行的编程语言之一是Java编程语言[3],它是一种面向对象的编程语言,它使用由基于堆栈的虚拟机执行的字节码指令.Java是围绕字节码而不是汇编语言构建的,这一事实提供了几个优势--例如,如果上述平台存在虚拟机实现,那么一次编写的代码可以在不同的平台上执行.从逆向工程的角度来看,这意味着只需要处理字节码,而与汇编语言相比,字节码包含的指令更少.

因此,为了将Java字节码转换为源代码,必须要在当前的最新Java版本(10)附近围绕200个不同的指令(4)进行转换,相比较而言,英特尔处理器组装指令集[5]包含约2000个不同的指令似乎是一个更容易的任务.

这样的一个任务可以通过名为“反编译器”[1]的软件来执行,它可以将二进制工件以一定的精度转换成源代码.Java编程语言中存在几种反编译器,本文的目的是比较这些反编译器,以便为软件开发人员提供建议.

本文的结构如下.第二部分给出了Java编程语言反编译软件的选择列表.第三部分简要介绍了Java编程语言二进制文件格式和字节码指令.第四部分给出了反编译软件使用的Java字节码反编译技术的几个例子.第五部分介绍了作者开发的一个测试用例.第六部分给出了测试用例反编译的结果,并对得到的结果进行了简短的分析.第七部分描述了附加的测试结果,以及使用本文作者定义的附加标准对反编译器进行比较.最后,对Java反编译软件进行了总结和建议.

2.JAVA编译器的软件

目前,有一些针对Java编程语言的反编译程序.为了选择要使用的程序,有必要对这些程序进行比较.在本节中,作者提供了此类软件的列表.反编译软件的列表是根据作者个人使用反编译软件的经验和作者在目前工作场所的调查结果编制的,目的是来确定其他程序员会首选什么软件来解决这类任务:

bull; JD Project[6]是一个模块化的反编译器,可以作为一个独立的应用程序运行,也可以集成到开发环境中,比如Eclipse[7]或Intellij IDEA[8].

bull; CFR[9]以库的形式分发,库中包含命令行接口(CLI),也可以用作其他软件的一部分.

bull; Procyon[10]是一个可以集成到其他应用程序并包含CLI的框架.它有几个图形用户界面(GUI)实现.

bull; Fernflower[11]是Intellij IDEA[8]开发环境中使用的Java反编译器.它以库的形式分发,库中也有CLI接口.

上述作者对Java反编译软件的调查基于两个问题:

bull; 您熟悉哪些Java反编译程序?

bull; 您推荐使用哪种Java反编译器?总共有247人回答了这些问题.

调查结果见表1和表2.

表1

你熟悉哪些Java反编译程序

反编译程序

总共答案

Fernflower

200

JD Project

158

Procyon

141

CFR

50

JAD

2

表2

您推荐使用哪种Java反编译程序

反编译器

总共答案

Fernflower

121

JD Project

74

Procyon

44

CFR

8

调查结果显示,绝大多数人都熟悉Fernflower反编译软件并推荐使用,这可以解释为它是建立在公司使用的开发环境中的,这就是Intellij思想[8].

虽然目前也存在其他几种Java编程语言反编译器的实现;然而,在大多数情况下,这些实现都是过时的且不受支持的.因此,本文对上述四种反编译器进行了比较.

3.机器二进制文件格式

Java虚拟机(JVM)使用二进制.class文件,其中包含源代码编译[12]的结果.这些文件包含有关编译单元(基本上是一个Java类或接口)的所有必要信息,包括:

bull; 编译器的版本,生成给定的.class文件.这允许JVM检测它是否应该能够加载和执行 给定的文件.

bull; 常量池,包含在给定编译单元中使用的各种字符串、类和接口名、字段和方法名以及其 他常量.

bull; 访问标志决定了给定编译单元的可见性和类型,这个信息定义了文件中包含的实际类是否可以被实例化和子类化,以及如何被实例化和子类化.

bull; 基类和接口的信息,给定编译单元继承自或实现.

bull; 字段和方法列表以及它们的访问标志和其他修饰符.

bull; 类的属性、字段和方法,用于确定关于上述编译单元的组件的附加信息.其中一个属性 是方法的际代码,其他属性表示可以在运行中使用的不同信息,例如注释,它是附加到给定

成员的语法元数据,或者是在所选方法执行期间可能抛出的异常列表.

code属性包含在适当方法调用期间使用的实际字节码指令清单.正如前面提到的,JVM字节码包含大约200条指令,并且可分为以下几组:

bull; 数学运算——这些指令用于实际的数学运算表示(例如,DADD指令汇总了两个双类型变量),以及堆栈顶部的常量加载(例如,ICONST_0hellip;hellip;ICONST_5指令允许加载0到5之间的整数).

bull; 堆栈操作——JVM是基于堆栈的虚拟机,这意味着它不使用任何类型的寄存器.相反,所有的局部变量都被加载到堆栈中,并可以在其上进行处理.这些指令允许读写信息包含在堆栈的顶部(例如,ALOAD允许推栈对象,而ASTORE获取并存储在本地变量),以及创建新的对象在堆栈的顶部(新允许创建一个新对象,而NEWARRAY给定类型的创建一个新的数组).这个组中的一些指令还意味着复制对象(DUP在堆栈顶部创建一个变量的副本并将其推到顶部),或者在不存储任何局部变量(POP)的情况下将它们从堆栈中删除.

bull; 类型转换指令——例如,D2I将堆栈顶部的double类型变量转换为int类型,并将结果推送到堆栈顶部.

bull; 类型检查指令,允许检查堆栈顶部变量的类型,并用检查结果(INSTANCEOF)替换它,或抛出运行时异常(CHECKCAST).

bull; 数值类型比较指令——例如,比较LCMP与堆栈顶部的两个长类型变量.

bull; 同步指令MONITORENTER和MONITOREXIT,用于获取对给定资源的互斥访问.

bull; 方法调用指令,例如INVOKEVIRTUAL,允许以不同的方式调用方法.

bull; 允许被调用的方法将其调用结果返回给其他运行代码的指令——例如,ARETURN允许使用对象作为调用结果,而return意味着该方法根本没有返回任何结果.

bull; 分支指令,用于在代码执行期间更改程序流.JVM同时具有条件指令(例如,如果引用的两个对象相同,IFACMP_EQ将更改流)和无条件分支指令(GOTO).还存在用于开关语言构造处理的特殊指令,例如,TABLESWITCH.

bull; 编译后的Java代码中不包含调试器指令断点.相反,调试器动态地注入这条指令.

bull; ATHROW——用于抛出异常的指令.

bull; ARRAYLENGTH——允许获取堆栈顶部数组长度的指令.

bull; NOP ——一个空指令.

class文件中的每个方法都有关于正在使用的局部变量的信息.它可能包含变量名的信息,也可能不包含变量名的信息——这取决于编译Java代码的方式.如果在编译过程中省略了局部变量名,那么只有关于局部变量逻辑号(索引)和类型的信息.

4.JVM字节码反编译技术

从上一节可以看出,反编译的Java字节码需要提取. class文件信息等其成员字段和方法,将适当的方法字节码转换为源代码和添加额外的信息访问旗帜类文件的所有部分.

在本文中,作者主要关注字节码转换的可能性,因为其他反编译任务可以通过提取必要的信息和使用简单的转换技术以简单的方式处理.

至于字节码,有必要了解大多数JVM字节码指令也可以用非常简单和直接的方式处理.在本例中,作者讨论的是除分支之外的所有字节码指令组.反编译器还需要在方法调用期间跟踪JVM堆栈的状态,因此可以确定哪些对象正在堆栈上加载并从中读取.还需要分析局部变量表来确定在方法调用期间使用哪些局部变量.作者想提供几个关于这些指令组的反编译技术如何工作的例子.

第一个例子如图1所示.在这种情况下,代码本身由三个数学指令组成——两个加载整数常量在堆栈的顶部,以及第三个求和给出整数.给定字节码示例中的最后一条指令告诉JVM使用堆栈顶部的变量作为方法的返回值.

图1所示.使用数学操作的JVM字节码.

要从给定的字节码片段恢复源代码,反编译器必须跟踪在这个字节码执行期间实际发生了什么.可以看到,由于第一个指令调用整数常量1被放在堆栈的顶部,这将导致以下堆栈状态:[1].第二条指令将整数常量2放在堆栈的顶部,因此堆栈变为:[2,1].然后下一条指令删除两个栈顶成员,将它们加起来,并将这个数学运算的结果放在栈顶,这样栈就变成了[1 2].最后,last字节码指令告诉JVM使用堆栈顶部的变量作为方法返回值.根据这些信息,可以看到给定的字节码片段对应于图2中所示的Java源代码.

图2所示.第一个字节码片段反编译结果.

图3显示了类似的字节码片段,唯一的区别是使用了局部变量而不是整数常量.

图3所示.使用数学操作和本地变量的JVM字节码.

这个字节码片段的反编译逻辑与前面的示例相同:反编译器应该跟踪每次执行指令时堆栈的状态,并使用这些信息重新构建源代码.当在字节码指令中使用局部变量时,反编译器应该引用适当方法的局部变量表,以确定是否存在实际的变量名.图4显示了这个字节码反编译结果的两个可能的结果——第一个假定局部变量名称存在,而第二个假定这些信息被在编译过程中,和反编译器来生成基于局部变量的指标变量名称表.

图4所示.第二个字节码片段反编译结果.

可以看出,在不考虑分支指令的情况下,反编译器的任务将是重建在适当的字节码指令调用期间发生的事情,并根据其工作发出适当的语法结构.

如果分支指令也出现在字节码中,则有必要分析控制流被分支指令重定向到何处.图5提供了带有分支指令的字节码的第一个示例.

图5所示.第一个分支的例子.

在这里,比较两个局部整数变量,如果第二个变量小于第一个,则出现控制流重定向.它的目标是分支指令之后的标签,因此反编译器应该能够确定这种分支对应于if语言结构.可以在分支指令之后找到的指令,依次对应于if语句的else部分.因此,反编译结果如图6所示.

图6所示.第一个分支实例反编译结果.

另一个分支示例是,作为控制流重定向目标的标签位于分支指令之前.这些情况对应于代码中的循环(while、for、dohellip;while).图7给出了这样一个字节码的例子.

图7所示.第二分支的例子.

这样的字节码应该被反编译成如图8所示的结果.

图8所示.第二个分支实例反编译结果.

值得一提的是,本节给出的所有示例都非常简单,真正的反编译器还应该能够处理嵌套分支指令和更复杂的控制流重定向.然而,这些似乎足以说明Java反编译器应该如何工作,以及在逆向工程过程中应该使用哪些信息.在下一节中,作者将讨论他为在更复杂的分支代码上进行反编译能力测试而开发的一个测试用例.

5.开发测试用例

为了测试Java反编译器如何处理复杂的分支情况

剩余内容已隐藏,支付完成后下载完整资料


资料编号:[19878],资料为PDF文档或Word文档,PDF文档可免费转换为Word

您需要先支付 30元 才能查看全部内容!立即支付

企业微信

Copyright © 2010-2022 毕业论文网 站点地图