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過度優化又說與源碼不符還不好弄
Java逆向基礎之靜態變量存取