Java反汇编入门教程
今天刚刚接触到java的反汇编,所以想写一篇文章给大家分享一下。
- 预备知识
学习反汇编首先应该首先了解JVM的内存模型,这里简单介绍一下。
JVM的内存模型,如下图
其中方法区和堆是线程共享的,java栈、程序计数器、本地方法栈是线程私有的。本博客主要是反汇编入门,我会举一个栗子,需要对java栈理解才能明白接下来的栗子。
-
程序执行过程
程序开始执行的时候,JVM会调用main函数,首先main函数会压入栈中,main函数调用其他函数,其他函数依次入栈,然后函数一层层返回直到main函数结束,程序结束。
-
Java栈
说java帧先说栈帧的概念
栈帧(Stack Frame) 是用于虚拟机执行时方法调用和方法执行时的数据结构,它是虚拟栈数据区的组成元素。每一个方法从调用到方法返回都对应着一个栈帧入栈出栈的过程。
每一个栈帧在编译程序代码的时候所需要多大的局部变量表,多深的操作数栈都已经决定了,并且写入到方发表的 Code 属性之中,一次一个栈帧需要多少内存,不会受到程序运行期变量数据的影响,仅仅取决于具体的虚拟机实现。
一个线程中方法调用可能很长,很多方法都处于执行状态。对于执行引擎来说,只有处于栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与之相关联的方法称为当前方法(Current Method)。
在概念模型上,典型的栈帧主要由 局部变量表(Local Stack Frame)、操作数栈(Operand Stack)、动态链接(Dynamic Linking)、返回地址(Return Address)组成,如下图所示
- 栗子
上面把需要掌握的基本要点已经介绍完了。下面我们直接来一个栗子,在详细的讲解。直接上代码,如下
public class Main {
public static void main(String[] args) {
test();
}
public static void test(){
int i = 2;
int j = 3;
int k = i + j;
System.out.println(k);
}
}
代码很简单,仅仅是一个main函数调用一个test方法,虽然是一个很简单的程序,内存中是如何执行,就得反汇编。得到反汇编的步骤。
-
打开cmd,进入到我们源程序的目录,输入命令:java Main.java
得到Main.class。 -
在当前目录中输入命令: javap -c 会看到
这就是生成的汇编代码
main函数
0: invokestatic #16 // Method test:()V main函数调用test函数
test函数
code:
0.iconst_2 //将整数2保存到操作数栈中
1.istore_0 //将操作数栈顶的数保存到局部变量表的变量0中(这里注意操作数栈会将栈顶的数弹栈)
2.iconst_3 //将整数3保存到操作数栈中
3.istore_1 //将操作数栈顶的数保存到局部变量表的变量1中
4.iload_0 //将局部变量表变量0保存到栈顶
5.iload_1 //将局部变量表变量0保存到栈顶
6.iadd //将栈顶两int类型数相加,结果入栈
7.istore_2 //将操作数栈顶的数保存到局部变量表的变量2中
…后面的代码就是输出,返回main函数
这样看汇编代码执行的逻辑和我们源码逻辑是一样的。希望能够帮助大家!汇编小白,希望勿喷