Java逆向系列-基础指令:静态变量存取
注意:静态变量static可以多次赋值,不能多次赋值的是final static
线性同余伪随机数算法LCG 算法数学上基于公式:
X(n+1) = (a * X(n) + c) % m
其中,各系数为:
模m, m > 0
系数a, 0 < a < m
增量c, 0 <= c < m
原始值(种子) 0 <= X(0) < m
其中参数c, m, a比较敏感,或者说直接影响了伪随机数产生的质量。
一般而言,高LCG的m是2的指数次幂(一般2^32或者2^64),因为这样取模操作截断最右的32或64位就可以了。多数编译器的库中使用了该理论实现其伪随机数发生器rand()。
这里m取2^32,a取1664525,c取1013904223
LCG算法实现例子
public class LCG
{
public static int rand_state;
public void my_srand (int init)
{
rand_state=init;
}
public static int RNG_a=1664525;
public static int RNG_c=1013904223;
public int my_rand ()
{
rand_state=rand_state*RNG_a;
rand_state=rand_state+RNG_c;
return rand_state & 0x7fff;
}
}
编译
javac LCG.java
反编译
javap -c -verbose LCG.class
静态块的初始化
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #5 // int 1664525
2: putstatic #3 // Field RNG_a:I
5: ldc #6 // int 1013904223
7: putstatic #4 // Field RNG_c:I
10: return
ldc #5 取常量1664525压栈
putstatic #3 从栈顶取值,存入静态变量RNG_a:I中
ldc #6 取常量1013904223压栈
putstatic #4 从栈顶取值,存入静态变量RNG_c:I中
这里putstatic实现了给静态变量初始化值。
下面的my_srand()函数将输入值存储到rand_state中
public void my_srand(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iload_1
1: putstatic #2 // Field rand_state:I
4: return
iload_1 //将第一个参数(init)压入栈,为什么不是iload_0?iload_0已经在默认生成的构造方法中使用了
(iload_0在构造方法中将this压入栈顶)
putstatic #2 //取出栈顶的init的值,将值保存至静态变量rand_state:I
这里补充说明一下,不知道是译者还是原作者的问题,这个存的值应该是类的初始化的时候的stack分的静态变量存储区域,不是所说的第二存储位
再看my_rand()
public int my_rand();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field rand_state:I
3: getstatic #3 // Field RNG_a:I
6: imul
7: putstatic #2 // Field rand_state:I
10: getstatic #2 // Field rand_state:I
13: getstatic #4 // Field RNG_c:I
16: iadd
17: putstatic #2 // Field rand_state:I
20: getstatic #2 // Field rand_state:I
23: sipush 32767
26: iand
27: ireturn
原文评论了17的putstatic #2和20的getstatic #2效率不高,实际上这只是java语句的翻译而已
试试把
public int my_rand ()
{
rand_state=rand_state*RNG_a;
rand_state=rand_state+RNG_c;
return rand_state & 0x7fff;
}
改成
public int my_rand ()
{
rand_state=rand_state*RNG_a+RNG_c;
return rand_state & 0x7fff;
}
再看这部分的反编译
public int my_rand();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field rand_state:I
3: getstatic #3 // Field RNG_a:I
6: imul
7: getstatic #4 // Field RNG_c:I
10: iadd
11: putstatic #2 // Field rand_state:I
14: getstatic #2 // Field rand_state:I
17: sipush 32767
20: iand
21: ireturn
这样就把原来的20行去掉了,这个应该在源码方面优化的就别交给JVM去优化了,JVM过度优化又说与源码不符还不好弄
本文参考:逆向工程权威指南.下册.pdf 和http://blog.51cto.com/7317859/2105269