阅读 182

编译与反编译,让字节码说人话

编译

什么是编译?

提起编译,就不得不提起我们的计算机语言啦。计算机语言指用于人与计算机之间通讯的语言,是人与计算机之间传递信息的媒介。它包括以下三种类型 :

机器语言 :

机器语言是以二进制代码表示的,计算机能够直接识别和执行的一种机器指令的集合,具有灵活、直接执行和速度快的特点。

然而,不同型号计算机的机器语言是不相通的,这也就导致了按着一种计算机的机器指令编制的程序,无法在另一种计算机上运行。

汇编语言 :

汇编语言是机器语言的初步抽象,它采用助记符来代替和表示一些特定低级机器语言的操作。其中,助记符是一种便于人们记忆,并能描述指令功能和指令操作数的符号,一般由表明该种指令功能的英语单词或其缩写构成,如ADD表示加法,MOV表示传送,SUB表示减法等。

汇编语言只是让使用者,即程序员们更易记住和使用,并不被计算机所认识。所以,想要让计算机执行汇编代码,需要首先将汇编程序转换成对应的机器语言代码。这一过程被称为汇编过程。

高级语言 :

机器语言与汇编语言,两者是几乎很少或完全没有做任何语法抽象的,它们更接近硬件,且不可在不同的硬件中移植,我们通常称其为低级语言。而与之相对的,那些进行了高度封装了的编程语言,则被称为是高级语言。

高级语言是以人类的日常语言为基础的一种编程语言,使用一般人易于接受的文字来表示(如汉字、不规则英文,或其他外语),从而使程序的编写更加容易,亦具有较高的可读性。

那么,如何将程序员写出来的高级语言转换成计算机认识的低级语言,然后让计算机去执行它们呢?这个转换的过程,就是我们的编译啦!

编译是如何进行的?

以 Java 语言为例,Java 作为一种高级语言,想要被执行,就需要通过编译的手段将其转换为机器语言。而这个转换,一共要经过两个步骤 :

  • 由前端编译器,将 Java 文件编译成中间代码,即 .class 文件,也称字节码文件
  • 由后端编译器,将字节码文件编译成机器语言

其中,前端编译器主要是 javac 等,后端编译器主要是由各大虚拟机实现的,如 HotSpot 中的 JIT 编译器。

反编译

什么是反编译?

既然通过编译器将高级语言转换为低级语言的过程称为编译,那么通过低级语言进行反向工程,获取源代码的过程自然就叫做反编译啦。

虽然将机器语言直接反编译为源代码是一个十分困难的过程,但是,如果将目标瞄准中间代码,这个过程就显得简单许多了。就像我们虽然不能把经过虚拟机编译后的机器语言进行反编译,但是将 javac 得到的 .class 文件进行反编译还是可行的。

而这个将字节码文件转换成 Java 文件的过程,就是我们常说的 Java 的反编译。

如何让字节码说人话?

哼哼,反编译工具来一把,.class从此讲Java。比如说我们有这样一个简单的 Demo :

package demo;

public class Demo {
    public static void main(String[] args) {
        Integer a = 1;
        System.out.println(a);
    }
}
复制代码

javac对它进行编译,得到对应的字节码文件之后,就轮到我们常用的反编译工具登场了 :

javap :

jdk 自带的反编译工具,可以对代码进行反编译,也可以查看 Java 编译器生成的字节码。但需要注意的是,javap 所生成的并不是 .java 文件,而是一种程序员能够看懂的字节码文件。

一般会使用 -c 进行反编译,得到的结果如下 :

jad :

这里 下载对应系统的压缩包,将解压出的 jad 文件加入 jdk 的 bin 目录下,输入 jad 跳出如下帮助文档时,就说明可以用啦。

jad 的优势在于操作方便,且可以直接将 class 文件反编译为 Java 文件,对用户十分友好。比如相比起 javap,通过它进行的反编译就能让我们清晰看出这个从 int 到 Integer 的装箱过程,而这一过程能够帮助我们更好地理解一些编译器的中间操作。

cfr :

jad 虽然好用又方便,但遗憾的是已经很久没有更新了。在对于 Java7 生成的字节码进行反编译时,偶尔会出现不支持的问题,在对 Java8 的 lambda 表达式进行反编译时则彻底失败(指连 .jad 文件都不会生成)。

而作为它的替代方案,cfr 将是一个不错的选择。从 这里 下载对应系统的 jar 包就可以使用啦,反编译时需要将 .class 文件和 jar 包放在同一目录下。

它的优势在于支持包括 lambda 在内的 Java 众多新增语法特性,且依然在保持更新。一般来说使用它进行反编译的时候是需要带参数的,具体的参数信息可以参考帮助文档 :

总体来讲功能相当齐全,就是用起来感觉太麻烦了QAQ

idea 下的 cfr 插件 :

idea 下的 cfr 插件,有时候有奇效!

不需要手动编译生成 .class 文件,直接选中 .java 文件,然后右键选择 Show Bytecode outline,最终反编译出来的效果如下 :

和 cfr 一样,它也是支持 lambda 等语法的,比如这样 :

写在最后的碎碎念

本来是只准备写编译和反编译的啦,昨天写完之后突然感觉,哎只有这个会不会有点少,不如再加一个分析字节码的?然后就又撸了一点回去了,想着今天来把剩下的写完嘛...结果今天写着写着发现怎么越写越越越越越多!这样的话放在一起就又太长了,可恶。

于是!字节码的部分就被拆出来放进这里啦 :Class类文件结构分析 -- 听懂字节码的语言


参考文章 :juejin.im/post/5ceb4d…

关注下面的标签,发现更多相似文章
评论