Java逆向系列-基礎指令:函式
阿新 • • 發佈:2019-02-09
例子1,方法名的定義
public class HalfRandom
{
public static double f()
{
return Math.random()/2;
}
}
編譯
javac HalfRandom.java
反編譯
javap -c -verbose HalfRandom.class
... major version: 52 ... #2 = Methodref #16.#17 // java/lang/Math.random:()D #3 = Double 2.0d ... #12 = Utf8 ()D ... #16 = Class #20 // java/lang/Math #17 = NameAndType #21:#12 // random:()D #18 = Utf8 HalfRandom #19 = Utf8 java/lang/Object #20 = Utf8 java/lang/Math #21 = Utf8 random ... public static double f(); descriptor: ()D flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=0, args_size=0 0: invokestatic #2 // Method java/lang/Math.random:()D 3: ldc2_w #3 // double 2.0d 6: ddiv 7: dreturn LineNumberTable: line 5: 0
invokestatic #2 呼叫常量#2定義的函式
函式名定義在常量池的Methodref中,它定義類,方法名,方法返回型別
常量#2中,可以看到它是由#16.#17拼接,#16定義了類名 java/lang/Math,#17是方法名和返回型別名random:()D
常量#17中,它是由#21:#12拼接,#21定義了方法名random,#12定義了返回型別名()D
()D的解釋 ,括號內沒有東西表示括號內無引數,D表示返回型別為double,如果是V則為void
這種方式
1)JVM可以檢查資料型別的正確性:
2)java反編譯器可以從被編譯的類檔案中修改資料型別。
再看"hello,world!"的例子
public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("Hello, World");
}
}
反編譯
... major version: 52 ... #2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #18 // Hello, World #4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V ... #16 = Class #23 // java/lang/System #17 = NameAndType #24:#25 // out:Ljava/io/PrintStream; #18 = Utf8 Hello, World #19 = Class #26 // java/io/PrintStream #20 = NameAndType #27:#28 // println:(Ljava/lang/String;)V ... #23 = Utf8 java/lang/System #24 = Utf8 out #25 = Utf8 Ljava/io/PrintStream; #26 = Utf8 java/io/PrintStream #27 = Utf8 println #28 = Utf8 (Ljava/lang/String;)V ... public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello, World 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 5: 0 line 6: 8
getstatic #2 獲取System.out的引用入棧
ldc #3 將字串Hello, World入棧
invokevirtual #4 呼叫println()方法,這裡需要傳兩個引數,引數從棧中獲取,1先將Hello, World出棧傳入(Ljava/lang/String;),2將System.out的引用出棧傳入java/io/PrintStream的引用
再看beep的函式呼叫(輸出計算機報警的蜂鳴聲)
public class bee
{
public static void main(String[] args)
{
java.awt.Toolkit.getDefaultToolkit().beep();
}
}
反編譯
...
major version: 52
...
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: invokestatic #2 // Method java/awt/Toolkit.getDefaultToolkit:()Ljava/awt/Toolkit;
3: invokevirtual #3 // Method java/awt/Toolkit.beep:()V
6: return
LineNumberTable:
line 5: 0
line 6: 6
invokestatic #2 呼叫java.awt.Toolkit.getDefaultToolkit()方法並將返回結果的引用壓入棧頂
invokevirtual #3 呼叫beep()函式,其中需要傳引用,把objectref從棧頂彈出傳入java/awt/Toolkit
本文參考:逆向工程權威指南.下冊.pdf 和http://blog.51cto.com/7317859/2105269