诸葛不亮 发表于 2013-2-3 14:39:22

CLASS 文件使用例子四--AOP字节码增强探索二

在上一篇中我们分析了
 
 
public class HelloWorld{      public static void main(String [] arvgs){          System.out.println("before log");          System.out.println("hello world");      System.out.println("after log");       }    }  和
 
public class HelloWorld{      public static void main(String [] arvgs){      System.out.println("hello world");   }    }  的class文件,最后我们是希望通过直接操作class文件能将简单版本(第二段代码)的行为修改为复杂版本(第一段代码);接下去我们看一下要做的事情:
 
根据上一篇的分析,我们只需要做两件事情,第一步是要新增4个常量,其中两个为constant_UTF8类型;两个为constant_String ,对应到新增的before log和after log;第二步是要修改main 函数,改变他的行为;
 
为了方便查阅:我先把简单版本初始的class文件给出:
 
 
00000000h: CA FE BA BE 00 00 00 32 00 1D 0A 00 06 00 0F 09 ; 漱壕...2........00000010h: 00 10 00 11 08 00 12 0A 00 13 00 14 07 00 15 07 ; ................00000020h: 00 16 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 ; .....<init>...()00000030h: 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E ; V...Code...LineN00000040h: 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 ; umberTable...mai00000050h: 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 ; n...([Ljava/lang00000060h: 2F 53 74 72 69 6E 67 3B 29 56 01 00 0A 53 6F 75 ; /String;)V...Sou00000070h: 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 ; rceFile...HelloW00000080h: 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 ; orld.java.......00000090h: 17 0C 00 18 00 19 01 00 0B 68 65 6C 6C 6F 20 77 ; .........hello w000000a0h: 6F 72 6C 64 07 00 1A 0C 00 1B 00 1C 01 00 0A 48 ; orld...........H000000b0h: 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 ; elloWorld...java000000c0h: 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A ; /lang/Object...j000000d0h: 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 ; ava/lang/System.000000e0h: 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F ; ..out...Ljava/io000000f0h: 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 ; /PrintStream;...00000100h: 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 ; java/io/PrintStr00000110h: 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 ; eam...println...00000120h: 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 ; (Ljava/lang/Stri00000130h: 6E 67 3B 29 56 00 21 00 05 00 06 00 00 00 00 00 ; ng;)V.!.........00000140h: 02 00 01 00 07 00 08 00 01 00 09 00 00 00 1D 00 ; ................00000150h: 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 ; .......*?.?...00000160h: 00 0A 00 00 00 06 00 01 00 00 00 01 00 09 00 0B ; ................00000170h: 00 0C 00 01 00 09 00 00 00 25 00 02 00 01 00 00 ; .........%......00000180h: 00 09 B2 00 02 12 03 B6 00 04 B1 00 00 00 01 00 ; ..?...?.?....00000190h: 0A 00 00 00 0A 00 02 00 00 00 03 00 08 00 04 00 ; ................000001a0h: 01 00 0D 00 00 00 02 00 0E                      ; .........  
 
接下去我们开始修改:
1、修改常量池大小,由28修改为32,就是将0x 1D 修改为 21;
2、找到常量池的结束点:0X 3B 29 56 ;在后面增加4个常量:
     08 00 1F
     08 00 20
     01 00 0A  62 5 66 6F 72 65 20 6C 6F 67
     01 00 09  61 66 74 65 72 20 6C 6F 67
第一个常量表示constant_String 类型 引用到第31号常量
第二个常量表示constant_String 类型 引用到第32号常量
第三个常量表示constant_UTF8 类型 值为 before log
第四个常量表示constant_UTF8 类型 值为 after log
 
然后找到main方法:
3、首先找到code处;B2 00 02 12 03 B6 00 04 B1;从上一篇可以发现这段code其实就是System.out.println("hello world");
于是我们在其前后要各增加一段代码:
在前面增加 B2 00 02 12 1D B6 00 04 表示  System.out.println("before log")
在后面增加 B2 00 02 12 1E B6 00 04 表示  System.out.println("after log")
总体就是 B2 00 02 12 03 B6 00 04 B1  改为 B2 00 02 12 1D B6 00 04 B2 00 02 12 03 B6 00 04 B2 00 02 12 1E B6 00 04 B1
 
4、可以发现第三步将代码量增加了16个长度,所以需要修改两处地方,第一次是code的长度由9变为25 (也就是ox09--->ox 19);第二处就是main的长度由37变为53(也就是 ox 25--->ox 35)
 
经过上面的4步就完成了整个修改;最终如下:
 
 
 
00000000h: CA FE BA BE 00 00 00 32 00 21 0A 00 06 00 0F 09 ; 漱壕...2.!......00000010h: 00 10 00 11 08 00 12 0A 00 13 00 14 07 00 15 07 ; ................00000020h: 00 16 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 ; .....<init>...()00000030h: 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E ; V...Code...LineN00000040h: 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 ; umberTable...mai00000050h: 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 ; n...([Ljava/lang00000060h: 2F 53 74 72 69 6E 67 3B 29 56 01 00 0A 53 6F 75 ; /String;)V...Sou00000070h: 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 ; rceFile...HelloW00000080h: 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 ; orld.java.......00000090h: 17 0C 00 18 00 19 01 00 0B 68 65 6C 6C 6F 20 77 ; .........hello w000000a0h: 6F 72 6C 64 07 00 1A 0C 00 1B 00 1C 01 00 0A 48 ; orld...........H000000b0h: 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 ; elloWorld...java000000c0h: 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A ; /lang/Object...j000000d0h: 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 ; ava/lang/System.000000e0h: 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F ; ..out...Ljava/io000000f0h: 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 ; /PrintStream;...00000100h: 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 ; java/io/PrintStr00000110h: 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 ; eam...println...00000120h: 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 ; (Ljava/lang/Stri00000130h: 6E 67 3B 29 56 08 00 1F 08 00 20 01 00 0A 62 65 ; ng;)V..... ...be00000140h: 66 6F 72 65 20 6C 6F 67 01 00 09 61 66 74 65 72 ; fore log...after00000150h: 20 6C 6F 67 00 21 00 05 00 06 00 00 00 00 00 02 ;log.!..........00000160h: 00 01 00 07 00 08 00 01 00 09 00 00 00 1D 00 01 ; ................00000170h: 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 00 ; ......*?.?....00000180h: 0A 00 00 00 06 00 01 00 00 00 01 00 09 00 0B 00 ; ................00000190h: 0C 00 01 00 09 00 00 00 35 00 02 00 01 00 00 00 ; ........5.......000001a0h: 19 B2 00 02 12 1D B6 00 04 B2 00 02 12 03 B6 00 ; .?...?.?...?000001b0h: 04 B2 00 02 12 1E B6 00 04 B1 00 00 00 01 00 0A ; .?...?.?.....000001c0h: 00 00 00 0A 00 02 00 00 00 03 00 08 00 04 00 01 ; ................000001d0h: 00 0D 00 00 00 02 00 0E                         ; ........ 运行结果如下:

http://dl.iteye.com/upload/attachment/0066/9252/fefca9b9-752e-3919-9c9d-4c00d882f1ae.jpg
 
 
具体的修改点可以查看下图
 
http://dl.iteye.com/upload/attachment/0066/9267/1b86f737-2adc-3325-b571-7278cb1e7964.jpg
 
页: [1]
查看完整版本: CLASS 文件使用例子四--AOP字节码增强探索二