Java逆向基礎之靜態變數存取

lightwing發表於2021-09-09


注意:靜態變數static可以多次賦值,不能多次賦值的是final static

線性同餘偽隨機數演算法LCG 演算法數學上基於公式:

X(n+1) = (a * X(n) + c) % m

其中,各系數為:

模m, m > 0

係數a, 0

增量c, 0

原始值(種子) 0

其中引數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: ()Vflags: ACC_STATICCode:stack=1, locals=0, args_size=00: ldc           #5                  // int 16645252: putstatic     #3                  // Field RNG_a:I5: ldc           #6                  // int 10139042237: putstatic     #4                  // Field RNG_c:I10: 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)Vflags: ACC_PUBLICCode:stack=1, locals=2, args_size=20: iload_11: putstatic     #2                  // Field rand_state:I4: 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: ()Iflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: getstatic     #2                  // Field rand_state:I3: getstatic     #3                  // Field RNG_a:I6: imul7: putstatic     #2                  // Field rand_state:I10: getstatic     #2                  // Field rand_state:I13: getstatic     #4                  // Field RNG_c:I16: iadd17: putstatic     #2                  // Field rand_state:I20: getstatic     #2                  // Field rand_state:I23: sipush        3276726: iand27: 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過度最佳化又說與原始碼不符還不好弄


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3407/viewspace-2813364/,如需轉載,請註明出處,否則將追究法律責任。

相關文章