1. 程式人生 > >Java逆向基礎之操作數棧

Java逆向基礎之操作數棧

java操作數棧指令

本文參考:http://www.vuln.cn/7115

本地變量和操作數棧

本地變量數組(Local Variable Array)

本地變量的數組包括方法執行所需要的所有變量,包括 this 的引用,所有方法參數和其他本地定義的變量。對於那些方法(靜態方法 static method)參數是以零開始的,對於實例方法,零為 this 保留。

所有的類型都在本地變量數組中占一個槽(entry),而 long 和 double 會占兩個連續的槽,因為它們有雙倍寬度(64-bit 而不是 32-bit)。

操作數棧(Operand Stack)

操作數棧在執行字節碼指令的時候使用,它和通用寄存器在 native CPU 中使用的方式類似。大多數 JVM 字節碼通過 pushing,popping,duplicating,swapping,或生產消費值的操作使用操作數棧。


看一個運算的例子

public class calc
{
public static int half(int a)
{
return a/2;
}
}

編譯

javac calc.java

反編譯

javap -c -verbose calc.class

反編譯結果

...
major version: 52
...
public static int half(int);
descriptor: (I)I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: iload_0
1: iconst_2
2: idiv
3: ireturn
LineNumberTable:
line 5: 0

iload_0 第0個變量(即變量a)壓入操作數棧

+-------+
| stack |
+-------+
|   a   |
+-------+

iconst_2 將2壓入操作數棧

+-------+
| stack |
+-------+
|   2   |
|   a   |
+-------+

idiv 操作數棧中的前兩個int相除,並將結果壓入操作數棧頂

+-------+
| stack |
+-------+
| result|
+-------+

ireturn 返回棧頂元素


例子2,復雜一點的例子,處理雙精度的值

public class calc
{
public static double half_double(double a)
{
return a/2.0;
}
}

反編譯

...
major version: 52
...
#2 = Double             2.0d
...
public static double half_double(double);
descriptor: (D)D
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=2, args_size=1
0: dload_0
1: ldc2_w        #2                  // double 2.0d
4: ddiv
5: dreturn
LineNumberTable:
line 5: 0

ldc2_w指令是從常量區裝載2.0d,另外,其他三條指令有d前綴,意思是他們使用double數據類型。


例子3,兩個參數

public class calc
{
public static int sum(int a, int b)
{
return a+b;
}
}

反編譯

...
major version: 52
...
public static int sum(int, int);
descriptor: (II)I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=2
0: iload_0
1: iload_1
2: iadd
3: ireturn
LineNumberTable:
line 5: 0

iload_0 第0個變量(即變量a)壓入操作數棧

+-------+
| stack |
+-------+
|   a   |
+-------+

iload_1 第1個變量(即變量b)壓入操作數棧

+-------+
| stack |
+-------+
|   b   |
|   a   |
+-------+

iadd 操作數棧中的前兩個int相加,並將結果壓入操作數棧頂

+-------+
| stack |
+-------+
| result|
+-------+

ireturn 返回棧頂元素


例子4,類型改為長整型

public class calc
{
public static long lsum(long a, long b)
	{
		return a+b;
	}
}

反編譯

...
major version: 52
...
public static long lsum(long, long);
descriptor: (JJ)J
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
0: lload_0
1: lload_2
2: ladd
3: lreturn
LineNumberTable:
line 5: 0

可以看到壓入第二個參數的時候為lload_2,可見lload_0占了兩個槽(entry)


例子5,混合運算

public class calc
{
public static int mult_add(int a, int b, int c)
{
return a*b+c;
}
}

反編譯

...
major version: 52
...
public static int mult_add(int, int, int);
descriptor: (III)I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=3
0: iload_0
1: iload_1
2: imul
3: iload_2
4: iadd
5: ireturn
LineNumberTable:
line 5: 0

iload_0 第0個變量(即變量a)壓入操作數棧

+-------+
| stack |
+-------+
|   a   |
+-------+

iload_1 第1個變量(即變量b)壓入操作數棧

+-------+
| stack |
+-------+
|   b   |
|   a   |
+-------+

imul 操作數棧中的前兩個int相乘,並將結果壓入操作數棧頂

+-------+
| stack |
+-------+
|result1|
+-------+

iload_2 第2個變量(即變量c)壓入操作數棧

+-------+
| stack |
+-------+
|   c   |
|result1|
+-------+

iadd 操作數棧中的前兩個int相加,並將結果壓入操作數棧頂

+-------+
| stack |
+-------+
|result2|
+-------+

ireturn 返回棧頂元素


Java逆向基礎之操作數棧