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

简介:

最近重新再看<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

目录
相关文章
|
3月前
|
Java 数据库连接 mybatis
AnnotationFormatError: Invalid default: public abstract java.lang.Class org.mybatis.spring.annotatio
AnnotationFormatError: Invalid default: public abstract java.lang.Class org.mybatis.spring.annotatio
39 0
|
8月前
|
存储 安全 前端开发
jvm之.class文件解读(上)
jvm之.class文件解读(上)
|
8月前
|
安全 Java Maven
SpringBoot自定义classloader加密保护class文件
最近针对公司框架进行关键业务代码进行加密处理,防止通过jd-gui等反编译工具能够轻松还原工程代码,相关混淆方案配置使用比较复杂且针对springboot项目问题较多,所以针对class文件加密再通过自定义的classloder进行解密加载,此方案并不是绝对安全,只是加大反编译的困难程度,防君子不防小人,整体加密保护流程图如下图所示
209 2
|
Java Maven
maven项目右键new没有java class
maven项目右键new没有java class
maven项目右键new没有java class
|
Java
jar的MANIFEST.MF配置了Class-Path, java -classpath设置无效
jar的MANIFEST.MF配置了Class-Path, java -classpath设置无效
145 0
Swagger2Config类内容编写
本文讲解Swagger2Config类内容编写。
120 0
|
JSON Java 数据格式