前言
在OpenJDK裡有一個
AsmTools
項目,用來生成正确的或者不正确的java
.class
檔案,主要用來測試和驗證。
我們知道直接修改
.class
檔案是很麻煩的,雖然有一些圖形界面的工具,但還是很麻煩。
以前我的辦法是用
ASMifier從
.class
檔案生成asm java代碼,再修改代碼,生成新的
.class
檔案,非常麻煩。
AsmTools
引入了兩種表示
.class
檔案的文法:
-
JASM
用類似java本身的文法來定義類和函數,位元組碼指令則很像傳統的彙編。
-
JCOD
整個
用容器的方式來表示,可以很清楚表示類檔案的結構。.class
重要的是兩種文法的檔案都是可以和
.class
互相轉換的。
建構AsmTools
官方文檔:
https://wiki.openjdk.java.net/display/CodeTools/How+to+build+AsmTools需要有jdk8和ant。
- clone代碼
hg clone http://hg.openjdk.java.net/code-tools/asmtools
- 編繹
打包出來的zip包裡有一個cd asmtools/build ant
。asmtools.jar
也可以在這裡下載下傳我建構的:
https://github.com/hengyunabc/hengyunabc.github.io/files/2188258/asmtools-7.0.zip測試簡單的java類
public class Test {
public static void main(String[] args) {
System.out.println("hello");
}
}
先用javac來編繹:
javac Test.java
檢視JASM文法結果
java -jar asmtools.jar jdis Test.class
結果:
super public class Test
version 52:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "hello";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
}
} // end Class Test
檢視JCOD文法結果
java -jar asmtools.jar jdec Test.class
class Test {
0xCAFEBABE;
0; // minor version
52; // version
[] { // Constant Pool
; // first element is empty
class #2; // #1
Utf8 "Test"; // #2
class #4; // #3
Utf8 "java/lang/Object"; // #4
Utf8 "<init>"; // #5
Utf8 "()V"; // #6
Utf8 "Code"; // #7
Method #3 #9; // #8
NameAndType #5 #6; // #9
Utf8 "LineNumberTable"; // #10
Utf8 "LocalVariableTable"; // #11
Utf8 "this"; // #12
Utf8 "LTest;"; // #13
Utf8 "main"; // #14
Utf8 "([Ljava/lang/String;)V"; // #15
Field #17 #19; // #16
class #18; // #17
Utf8 "java/lang/System"; // #18
NameAndType #20 #21; // #19
Utf8 "out"; // #20
Utf8 "Ljava/io/PrintStream;"; // #21
String #23; // #22
Utf8 "hello"; // #23
Method #25 #27; // #24
class #26; // #25
Utf8 "java/io/PrintStream"; // #26
NameAndType #28 #29; // #27
Utf8 "println"; // #28
Utf8 "(Ljava/lang/String;)V"; // #29
Utf8 "args"; // #30
Utf8 "[Ljava/lang/String;"; // #31
Utf8 "SourceFile"; // #32
Utf8 "Test.java"; // #33
} // Constant Pool
0x0021; // access
#1;// this_cpx
#3;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // fields
} // fields
[] { // methods
{ // Member
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[] { // Attributes
Attr(#7) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70008B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#10) { // LineNumberTable
[] { // LineNumberTable
0 2;
}
} // end LineNumberTable
;
Attr(#11) { // LocalVariableTable
[] { // LocalVariableTable
0 5 12 13 0;
}
} // end LocalVariableTable
} // Attributes
} // end Code
} // Attributes
} // Member
;
{ // Member
0x0009; // access
#14; // name_cpx
#15; // sig_cpx
[] { // Attributes
Attr(#7) { // Code
2; // max_stack
1; // max_locals
Bytes[]{
0xB200101216B60018;
0xB1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#10) { // LineNumberTable
[] { // LineNumberTable
0 5;
8 6;
}
} // end LineNumberTable
;
Attr(#11) { // LocalVariableTable
[] { // LocalVariableTable
0 9 30 31 0;
}
} // end LocalVariableTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[] { // Attributes
Attr(#32) { // SourceFile
#33;
} // end SourceFile
} // Attributes
} // end class Test
從JASM/JCOD文法檔案生成類檔案
因為是等價表達,可以從JASM生成
.class
檔案:
java -jar asmtools.jar jasm Test.jasm
同樣可以從JCOD生成
.class
java -jar asmtools.jar jcoder Test.jasm
更多使用方法參考:
https://wiki.openjdk.java.net/display/CodeTools/Chapter+2#Chapter2-Jasm.1