使用javassist对.class文件进行修改

    xiaoxiao2024-06-01  93

    最近重新再看<Inside JVM>,对JAVA编译成的字节码结构很感兴趣,希望找个工具能够对.class文件进行的解析和查看。没找到,倒发现javaassist可以对字节码进行操作和修改。此工具是JBOSS项目的一部分,JBOSS实现AOP的基础。呵呵,开眼界了,原来我们可以直接对字节码文件进行修改,哪怕不知道源文件(跟反编译完全不同)。一个简单例子:

    import javassist.*; class Hello {     public void say() {         System.out.println("Hello");     } }

    public class Test {     public static void main(String[] args) throws Exception {         ClassPool cp = ClassPool.getDefault();         CtClass cc = cp.get("Hello");         CtMethod m = cc.getDeclaredMethod("say");         m.setBody("{System.out.println(/"shit/");}");         m.insertBefore("System.out.println(/"fuck/");");         Class c = cc.toClass();         Hello h = (Hello)c.newInstance();         h.say();     } }

    编译运行此文件,输出:

    fuck

    shit

    我们在

     CtMethod m = cc.getDeclaredMethod("say");   m.setBody("{System.out.println(/"shit/");}");

      m.insertBefore("System.out.println(/"fuck/");");

    修改了say()方法,改成了

    System.out.println("fuck");

    System.out.println("shit");

    这里的ClassPool是CtClass的容器,它读取class文件,并根据要求保存CtClass的结构以便日后使用,默认状态下是从当前的类装载器获得,当然你可以指定:

    pool.insertClassPath("/usr/local/javalib");

    当然,不仅仅是修改方法,你还可以新建一个class,利用makeClass()方法,如:

    ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("Point");

    还可以新增方法,下面是sample里的一个例子,同样的:

    package sample;

    import javassist.*; import java.lang.reflect.*;

    /*    A very simple sample program

       This program overwrites sample/Test.class (the class file of this    class itself) for adding a method g().  If the method g() is not    defined in class Test, then this program adds a copy of    f() to the class Test with name g().  Otherwise, this program does    not modify sample/Test.class at all.

       To see the modified class definition, execute:

       % javap sample.Test

       after running this program. */ public class Test {     public int f(int i) {      i++;     return i;     }

        public static void main(String[] args) throws Exception {  ClassPool pool = ClassPool.getDefault();

     CtClass cc = pool.get("sample.Test");  Test test=new Test();  Class c=test.getClass();  Method []method=c.getDeclaredMethods();  for(int i=0;i<method.length;i++){   System.out.println(method[i]);  }  try {      cc.getDeclaredMethod("g");      System.out.println("g() is already defined in sample.Test.");  }  catch (NotFoundException e) {      /* getDeclaredMethod() throws an exception if g()       * is not defined in sample.Test.       */      CtMethod fMethod = cc.getDeclaredMethod("f");      CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);      cc.addMethod(gMethod);      cc.writeFile(); // update the class file      System.out.println("g() was added.");  }     } } 第一次运行时,因为Test里并没有g()方法,所以执行

     CtMethod fMethod = cc.getDeclaredMethod("f");      CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);  //把f方法复制给g      cc.addMethod(gMethod);      cc.writeFile(); //更新class文件

         System.out.println("g() was added."); 打印:g() was added

    第2次运行时,因为以上步骤已经在class文件中增加了一个g方法,所以

     System.out.println("g() is already defined in sample.Test."); 打印:g() is already defined in sample.Test

     

    Javassist不仅能修改你自己的class文件,而且可以同样修改JDK自带的类库(废话,类库也是人写的^_^)具体请看它的tutorial

    文章转自庄周梦蝶  ,原文发布时间5.17

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)