java 操作数_Java逆向系列-基础指令:操作数栈

本地变量和操作数栈

本地变量数组(Local Variable Array)

本地变量的数组包括方法执行所需要的所有变量,包括 this 的引用,所有方法参数和其他本地定义的变量。对于那些方法(静态方法 static method)参数是以零开始的,对于实例方法,零为 this 保留。

所有的类型都在本地变量数组中占一个槽(entry),而 long 和 double 会占两个连续的槽,因为它们有双倍宽度(64-bit 而不是 32-bit)。

操作数栈(Operand Stack)

操作数栈(也可以称之为表达式栈(Expression 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 返回栈顶元素

本文参考:逆向工程权威指南.下册.pdf 和http://blog.51cto.com/7317859/2105269

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值